Skip to content

Commit 48df9e1

Browse files
committed
xml: make structs serializable, but enforce contracts
Also, tweak docs and add `no-external-dtd`. Increment version to 8.17.0.5. Related to: racket/scribble#498 Related to: racket#5282 Related to: racket/rhombus#644
1 parent 204c692 commit 48df9e1

File tree

8 files changed

+630
-39
lines changed

8 files changed

+630
-39
lines changed

pkgs/base/info.rkt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
;; In the Racket source repo, this version should change exactly when
1616
;; "racket_version.h" changes:
17-
(define version "8.17.0.4")
17+
(define version "8.17.0.5")
1818

1919
(define deps `("racket-lib"
2020
["racket" #:version ,version]))

pkgs/racket-doc/scribblings/reference/serialization.scrbl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ by deserialization produces a value with the same graph structure and
4040
mutability as the original value, but the serialized value is a plain
4141
tree (i.e., no sharing).
4242

43-
The following kinds of values are serializable:
43+
The following kinds of values are @deftech{serializable}:
4444

4545
@itemize[
4646

@@ -575,10 +575,10 @@ transfers the field values of this instance into @racket[x].}
575575

576576
@; ----------------------------------------------------------------------
577577

578-
@defthing[prop:serializable property?]{
578+
@defthing[prop:serializable struct-type-property?]{
579579

580580
This property identifies structures and structure types that are
581-
serializable. The property value should be constructed with
581+
@tech{serializable}. The property value should be constructed with
582582
@racket[make-serialize-info].}
583583

584584
@; ----------------------------------------------------------------------

pkgs/racket-doc/xml/xml.scrbl

Lines changed: 134 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
@interaction-eval[#:eval xml-eval (require xml)]
1414
@interaction-eval[#:eval xml-eval (require racket/list)]
1515
@interaction-eval[#:eval plist-eval (require xml/plist)]
16+
@(define reference '(lib "scribblings/reference/reference.scrbl"))
1617

1718
@title{XML: Parsing and Writing}
1819

@@ -38,7 +39,13 @@ It does not interpret namespaces either.
3839
[char (or/c #f exact-nonnegative-integer?)]
3940
[offset exact-nonnegative-integer?])]{
4041

41-
Represents a location in an input stream. The offset is a character offset unless @racket[xml-count-bytes] is @racket[#t], in which case it is a byte offset.}
42+
Represents a location in an input stream. The offset is a
43+
character offset unless @racket[xml-count-bytes] is
44+
@racket[#t], in which case it is a byte offset.
45+
46+
@history[
47+
#:changed "8.17.0.5" @elem{Added support for serialization with @racketmodname[racket/serialize].}
48+
]}
4249

4350
@defthing[location/c contract?]{
4451
Equivalent to @racket[(or/c location? symbol? #f)].
@@ -53,30 +60,83 @@ Represents a source location. Other structure types extend
5360
When XML is generated from an input stream by @racket[read-xml],
5461
locations are represented by @racket[location] instances. When XML
5562
structures are generated by @racket[xexpr->xml], then locations are
56-
symbols.}
63+
symbols.
64+
65+
@margin-note{Immediate instances of @racket[source] are not
66+
@tech[#:doc reference]{serializable}. The @racketmodname[xml] library
67+
only uses @tech[#:doc reference #:key "structure subtypes"]{subtypes}
68+
of @racket[source].}
69+
}
5770

5871
@deftogether[(
5972
@defstruct[external-dtd ([system string?])]
6073
@defstruct[(external-dtd/public external-dtd) ([public string?])]
6174
@defstruct[(external-dtd/system external-dtd) ()]
75+
@defthing[no-external-dtd external-dtd? #:value (external-dtd "")]
6276
)]{
6377

64-
Represents an externally defined DTD.}
78+
Represents an externally defined DTD.
79+
80+
As a special case, immediate instances of @racket[external-dtd]
81+
represent the @emph{absence} of an external DTD, and its @racket[system]
82+
field is ignored. The @racket[no-external-dtd] value is provided
83+
for clarity, but any immediate instance of @racket[external-dtd]
84+
has the same meaning.
85+
86+
@examples[
87+
#:eval xml-eval
88+
(define (show-doctype type)
89+
(write-xml (document (prolog '() type '())
90+
(element #f #f (document-type-name type) '() '())
91+
'())))
92+
(show-doctype (document-type 'html (external-dtd "ignored") #f))
93+
(show-doctype (document-type 'svg
94+
(external-dtd/public "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"
95+
"-//W3C//DTD SVG 1.1//EN")
96+
#f))
97+
(show-doctype (document-type 'greeting (external-dtd/system "hello.dtd") #f))
98+
]
99+
100+
@history[
101+
#:changed "8.17.0.5" @elem{Added support for serialization with @racketmodname[racket/serialize].}
102+
#:changed "8.17.0.5" @elem{Added @racket[no-external-dtd].}
103+
]}
65104

66105
@defstruct[document-type ([name symbol?]
67106
[external external-dtd?]
68107
[inlined #f])]{
69108

70-
Represents a document type.}
109+
Represents a document type. For examples, see @racket[external-dtd].
110+
111+
@history[
112+
#:changed "8.17.0.5" @elem{Added support for serialization with @racketmodname[racket/serialize].}
113+
]}
71114

72115
@defstruct[comment ([text string?])]{
73116

74-
Represents a comment.}
117+
Represents a comment.
118+
119+
@history[
120+
#:changed "8.17.0.5" @elem{Added support for serialization with @racketmodname[racket/serialize].}
121+
]}
75122

76123
@defstruct[(p-i source) ([target-name symbol?]
77124
[instruction string?])]{
78125

79-
Represents a processing instruction.}
126+
Represents a processing instruction.
127+
128+
@examples[
129+
#:eval xml-eval
130+
(write-xml (document (prolog (list (p-i #f #f 'xml "version=\"1.0\""))
131+
#f
132+
'())
133+
(element #f #f 'x)
134+
'()))
135+
]
136+
137+
@history[
138+
#:changed "8.17.0.5" @elem{Added support for serialization with @racketmodname[racket/serialize].}
139+
]}
80140

81141
@defthing[misc/c contract?]{
82142
Equivalent to @racket[(or/c comment? p-i?)]
@@ -86,21 +146,36 @@ Represents a processing instruction.}
86146
[dtd (or/c document-type #f)]
87147
[misc2 (listof misc/c)])]{
88148
Represents a document prolog.
89-
}
149+
150+
@history[
151+
#:changed "8.17.0.5" @elem{Added support for serialization with @racketmodname[racket/serialize].}
152+
]}
90153

91154
@defstruct[document ([prolog prolog?]
92155
[element element?]
93156
[misc (listof misc/c)])]{
94-
Represents a document.}
157+
Represents a document.
158+
159+
@history[
160+
#:changed "8.17.0.5" @elem{Added support for serialization with @racketmodname[racket/serialize].}
161+
]}
95162

96163
@defstruct[(element source) ([name symbol?]
97164
[attributes (listof attribute?)]
98165
[content (listof content/c)])]{
99-
Represents an element.}
166+
Represents an element.
167+
168+
@history[
169+
#:changed "8.17.0.5" @elem{Added support for serialization with @racketmodname[racket/serialize].}
170+
]}
100171

101172
@defstruct[(attribute source) ([name symbol?] [value (or/c string? permissive/c)])]{
102173

103-
Represents an attribute within an element.}
174+
Represents an attribute within an element.
175+
176+
@history[
177+
#:changed "8.17.0.5" @elem{Added support for serialization with @racketmodname[racket/serialize].}
178+
]}
104179

105180
@defthing[content/c contract?]{
106181
Equivalent to @racket[(or/c pcdata? element? entity? comment? cdata? p-i? permissive/c)].
@@ -115,20 +190,65 @@ Represents an attribute within an element.}
115190

116191
@defstruct[(entity source) ([text (or/c symbol? valid-char?)])]{
117192

118-
Represents a symbolic or numerical entity.}
193+
Represents a symbolic @deftech{entity} reference
194+
or a numerical @deftech{character reference}.
195+
196+
As a special case, this library parses references to the @deftech{predefined entities}
197+
into @racket[pcdata] values, so it does not generate @racket[entity] values containing
198+
@racket['lt], @racket['gt], @racket['amp], @racket['apos], or @racket['quot].
199+
Nonetheless, such @racket[entity] values may be created programmatically.
200+
201+
@examples[
202+
#:eval xml-eval
203+
(for/list ([s '(lt gt amp apos quot)])
204+
(with-output-to-string
205+
(λ ()
206+
(write-xml/content (entity #f #f s)))))
207+
(read-xml/element (open-input-string "<x> &lt;&gt;&amp;&apos;&quot; </x>"))
208+
]
209+
210+
@history[
211+
#:changed "8.17.0.5" @elem{Added support for serialization with @racketmodname[racket/serialize].}
212+
]}
119213

120214
@defstruct[(pcdata source) ([string string?])]{
121215

122-
Represents PCDATA content.}
216+
Represents textual content, i.e@._ what the
217+
@link["https://www.w3.org/TR/REC-xml/#dt-chardata"]{XML specification} calls
218+
@deftech{character data}.
219+
220+
More specifically, this library library has several representations for
221+
@tech{character data} corresponding to different concrete syntaxes in XML.
222+
The @racket[pcdata] struct represents character data that is neither
223+
encoded by a @tech{character reference} or user-defined @tech{entity},
224+
which use @racket[entity], nor written in a @racket[cdata] section.
225+
References to the @tech{predefined entities} can be represented by either @racket[pcdata]
226+
or @racket[entity], but this library always uses @racket[pcdata] when parsing.
227+
228+
@margin-note{The @racket[pcdata] struct is a bit of a misnomer.
229+
In XML, @litchar{PCDATA} is a keyword used to declare that an element contains
230+
``@link["https://www.w3.org/TR/REC-xml/#sec-mixed-content"]{mixed content},''
231+
i.e@._ @tech{character data} potentially interspersed with child elements,
232+
but the @racket[pcdata] struct specifically represents @tech{character data}.
233+
Historically, the term meant ``parsed character data.''
234+
}
235+
236+
@history[
237+
#:changed "8.17.0.5" @elem{Added support for serialization with @racketmodname[racket/serialize].}
238+
]}
123239

124240
@defstruct[(cdata source) ([string string?])]{
125241

126-
Represents CDATA content.
242+
Represents a CDATA section.
127243

128244
The @racket[string] field is assumed to be of the form
129245
@litchar{<![CDATA[}@nonterm{content}@litchar{]]>} with proper quoting
130246
of @nonterm{content}. Otherwise, @racket[write-xml] generates
131-
incorrect output.}
247+
ill-formed output.
248+
249+
@history[
250+
#:changed "8.17.0.5" @elem{Added support for serialization with @racketmodname[racket/serialize].}
251+
]}
132252

133253
@defstruct[(exn:invalid-xexpr exn:fail) ([code any/c])]{
134254

0 commit comments

Comments
 (0)