Revert "Revert "Made use of ::= in core libraries and defined a RebindError condition...
[cslatevm.git] / src / lib / xml.slate
blobe4def6df787d117637b1ca6548ea579348e85c1b
1 "This is a port of the Smalltalk YAXO XML parser. It was originally written
2 by Michael Reuger."
4 prototypes ensureNamespace: #XML.
6 XML define: #Node &parents: {Cloneable}.
8 n@(XML Node traits) contentsDo: block
9 [n].
11 n@(XML Node traits) elementsDo: block
12 [n].
14 n@(XML Node traits) firstTagNamed: name
15 "Return the first encountered node with the specified tag.
16 Pass the message on."
17 [| answer |
18   n elementsDo: [| :each | (answer := each firstTagNamed: name)
19     ifNotNil: [^ answer]].
20   Nil
23 n@(XML Node traits) firstTagNamed: name with: testBlock
24 "Return the first encountered node with the specified tag for which the block
25 returns True. Pass the message on."
26 [| answer |
27   n elementsDo: [| :each | (answer := each firstTagNamed: name with: testBlock)
28     ifNotNil: [^ answer]].
29   Nil
32 n@(XML Node traits) tagsNamed: name childrenDo: block
33 "Evaluate the block on all children that match."
35   n elementsDo: [| :each | each tagsNamed: name ifReceiverDo: block]
38 n@(XML Node traits) tagsNamed: name childrenDoAndRecurse: block
39 "Evaluate the block on all children that match and recurse."
41   n elementsDo: [| :each | each tagsNamed: name ifReceiverDoAndRecurse: block]
44 n@(XML Node traits) tagsNamed: name contentsDo: block
45 "Evaluate the block on all contents that match."
47   n elementsDo: [| :each | each tagsNamed: name contentsDo: block]
50 n@(XML Node traits) tagsNamed: name do: block
51 "Evaluate the block on all tags that match."
53   n elementsDo: [| :each | each tagsNamed: name do: block]
56 n@(XML Node traits) tagsNamed: name ifReceiverDo: block
57 "Default handler; only XML TagNode should handle this."
58 [n].
60 n@(XML Node traits) tagsNamed: name ifReceiverDoAndRecurse: block
61 "Recurse all children."
63   n elementsDo: [| :each | each tagsNamed: name ifReceiverDoAndRecurse: block]
66 n@(XML Node traits) tagsNamed: name ifReceiverOrChildDo: block
67 "Recurse all children."
69   n elementsDo: [| :each | each tagsNamed: name ifReceiverDo: block]
72 n@(XML Node traits) printOn: stream
73 "This is for normal printing compatibility."
75   n printXMLOn: (XML PrintStream newOn: stream)
78 n@(XML Node traits) printXMLOn: _
79 "Override this."
80 [n].
82 XML define: #NodeWithElements &parents: {XML Node}
83  &slots: {#elements -> ExtensibleArray new}.
85 n@(XML NodeWithElements traits) copy
86 [n clone `setting: #{#elements} to: {n elements copy}].
88 n@(XML NodeWithElements traits) printXMLOn: writer
90   n elements do: [| :each | each printXMLOn: writer]
93 XML define: #Document &parents: {XML NodeWithElements} &slots:
94  {#dtd -> ''.
95   #version -> ''.
96   #encoding -> ''.
97   #requiredMarkup -> ''}.
99 d@(XML Document traits) printXMLOn: writer
101   n version ifNotNil: [writer xmlDeclaration: n version].
102   resend
105 d@(XML Document traits) printCanonicalOn: stream
106 [| writer |
107   writer := XML PrintStream on: stream.
108   writer canonical := True.
109   d printXMLOn: writer
112 XML define: #Element &parents: {XML NodeWithElements} &slots:
113   {#name -> #''.
114    #contents -> ExtensibleArray new.
115    #attributes -> ExtensibleArray new}.
117 e@(XML Element traits) firstTagNamed: name
118 "Return the first node with the tag, or pass it on."
120   e name == name
121     ifTrue: [n]
122     ifFalse: [resend]
125 e@(XML Element traits) firstTagNamed: name with: testBlock
126 "Return the first node with the tag and that passes the test, or pass it on."
128   e name == name /\ [testBlock applyWith: e]
129     ifTrue: [n]
130     ifFalse: [resend]
133 e@(XML Element traits) tagsNamed: name contentsDo: block
134 "Call the block on all contents if the element's tag matches the given name,
135 then pass it on."
137   e name == name ifTrue: [e contentsDo: block].
138   resend
141 e@(XML Element traits) tagsNamed: name do: block
142 "Call the block on the element if its tag matches the given name,
143 then pass it on."
145   e name == name ifTrue: [block applyWith: e].
146   resend
149 e@(XML Element traits) tagsNamed: name ifReceiverDo: block
150 "Call the block on the element if the name matches."
152   e name == name ifTrue: [block applyWith: e]
155 e@(XML Element traits) tagsNamed: name ifReceiverDoAndRecurse: block
156 "Call the block on the element if the name matches. Then recurse through the
157 children."
159   e name == name ifTrue: [block applyWith: e].
160   resend
163 e@(XML Element traits) tagsNamed: name ifReceiverOrChildDo: block
164 "Call the block on the element if the name matches, and do the same for the
165 direct children only."
167   e name == name ifTrue: [block applyWith: e].
168   resend
171 e@(XML Element traits) contentsDo: block
173   e contents do: block
176 e@(XML Element traits) contentsString
178   e contents size == 1 /\ [e contents first is: XML StringNode]
179     ifTrue: [e contents first string]
180     ifFalse: ['']
183 e@(XML Element traits) contentsStringAt: name
185   (e elements at: name ifAbsent: [^ '']) string
188 e@(XML Element traits) printXMLOn: writer
190   writer startElement: e name attributeList: e attributes.
191   writer canonical not /\ [e isEmpty] /\ [e attributes isEmpty not]
192     ifTrue: [writer endEmptyTag: e name]
193     ifFalse: [
194       writer endTag.
195       e contentsDo: [| :content | content printXMLOn: writer].
196       resend.
197       writer endTag: e name]
200 e@(XML Element traits) isEmpty
201 "Treat the element as the joining of its elements and contents."
203   e elements isEmpty /\ [e contents isEmpty]
206 XML define: #ProcessingInstruction &parents: {XML Node} &slots:
207  {#target -> ''. #data -> ''}.
209 pi@(XML ProcessingInstruction traits) newForTarget: name data: string
210 [pi clone `setting: #{#target. #data} to: {name. string}].
212 "printXMLOn: defined after XML PrintStream is defined."
214 XML define: #StringNode &parents: {XML Node} &slots: {#string -> ''}.
216 sn@(XML StringNode traits) copy
217 [sn clone `setting: #{#string} to: {sn string copy}].
219 sn@(XML StringNode traits) newFor: string
220 [sn clone `setting: #{#string} to: {string}].
222 sn@(XML StringNode traits) printXMLOn: writer
224   writer pcData: sn string
227 (XML Translation ::= Dictionary new &capacity: 30) addAll: {
228   $\r -> '
'.
229   $\n -> '
'.
230   $\t -> '	'.
231   $& -> '&'.
232   $< -> '&lt;'.
233   $> -> '&gt;'.
234   $\' -> '&apos;'.
235   $\" -> '&quot;'
238 XML define: #PrintStream &parents: {Cloneable} &slots: {
239   #stack -> Stack new.
240   #stream.
241   #scanner.
242   #canonical -> False
245 w@(XML PrintStream traits) newOn: stream
246 [w clone `setting: #{#stack. #stream} to: {w stack new. stream}].
248 w@(XML PrintStream traits) attribute: name value: value
250   w stream ; ' ' ; name printString ; '="'.
251   w pcData: value.
252   w stream nextPut: $\".
253   w
256 w@(XML PrintStream traits) cdata: string
258   w stream ; '<![CDATA[' ; string ; ']]>'
261 w@(XML PrintStream traits) pcData: c
263   w stream ; (XML Translation at: c ifAbsent: [c as: String])
266 w@(XML PrintStream traits) comment: string
268   w stream ; '<!-- ' ; string ; ' -->'
271 pi@(XML ProcessingInstruction traits) printXMLOn: w@(XML PrintStream traits)
273   w stream ; '<?' ; pi target ; ' ' ; pi data ; '?>'
276 w@(XML PrintStream traits) pushTag: name
278   w stack push: name
281 w@(XML PrintStream traits) popTag: name
282 [| top |
283   top := w stack isEmpty
284     ifTrue: ['<empty>']
285     ifFalse: [w stack last].
286   top = name
287     ifTrue: [w stack pop]
288     ifFalse: [w error: 'Closing tag ' ; name ; ' doesn\'t match ' ; top]
291 w@(XML PrintStream traits) startTag: name
293   w stream ; '<' ; name.
294   "w canonical ifTrue: [w stream ; ' ']."
295   w pushTag: name
298 w@(XML PrintStream traits) endTag
300   w stream nextPut: $>.
301   w
304 w@(XML PrintStream traits) endTag: name
306   w popTag: name.
307   w stream ; '</' ; name.
308   w stream nextPut: $>.
309   w
312 w@(XML PrintStream traits) endEmptyTag: name
314   w popTag: name.
315   w stream ; '/>'.
316   w canonical ifFalse: [w stream nextPut: $\s].
317   w
320 w@(XML PrintStream traits) startElement: name attributes: attribs
322   w canonical ifFalse: [w stream nextPut: $\r].
323   w startTag: name.
324   (attribs keySet as: SortedArray) do: [| :key |
325     w attribute: key value: (attribs at: key)].
326   w
329 w@(XML PrintStream traits) xmlDeclaration: versionString
331   w canonical ifFalse: [
332     w stream ; '<?XML '.
333     w attribute: 'version' value: versionString.
334     w stream ; '?>'].
335   w