Renamed "Writer" types to "PrintStream" and appropriate variations.
[cslatevm.git] / src / lib / xml.slate
blobc5e5b4618f116eb235cc75d2d794d07fda0d64dd
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 define: #Translation &builder: [Dictionary new &capacity: 30])
228  addAll:
229  {$\r -> '
'.
230   $\n -> '
'.
231   $\t -> '	'.
232   $& -> '&'.
233   $< -> '&lt;'.
234   $> -> '&gt;'.
235   $\' -> '&apos;'.
236   $\" -> '&quot;'}.
238 XML define: #PrintStream &parents: {Cloneable}
239   &slots: {#stack -> Stack new. #stream. #scanner. #canonical -> False}.
241 w@(XML PrintStream traits) newOn: stream
242 [w clone `setting: #{#stack. #stream} to: {w stack new. stream}].
244 w@(XML PrintStream traits) attribute: name value: value
246   w stream ; ' ' ; name printString ; '="'.
247   w pcData: value.
248   w stream nextPut: $\".
249   w
252 w@(XML PrintStream traits) cdata: string
254   w stream ; '<![CDATA[' ; string ; ']]>'
257 w@(XML PrintStream traits) pcData: c
259   w stream ; (XML Translation at: c ifAbsent: [c as: String])
262 w@(XML PrintStream traits) comment: string
264   w stream ; '<!-- ' ; string ; ' -->'
267 pi@(XML ProcessingInstruction traits) printXMLOn: w@(XML PrintStream traits)
269   w stream ; '<?' ; pi target ; ' ' ; pi data ; '?>'
272 w@(XML PrintStream traits) pushTag: name
274   w stack push: name
277 w@(XML PrintStream traits) popTag: name
278 [| top |
279   top := w stack isEmpty
280     ifTrue: ['<empty>']
281     ifFalse: [w stack last].
282   top = name
283     ifTrue: [w stack pop]
284     ifFalse: [w error: 'Closing tag ' ; name ; ' doesn\'t match ' ; top]
287 w@(XML PrintStream traits) startTag: name
289   w stream ; '<' ; name.
290   "w canonical ifTrue: [w stream ; ' ']."
291   w pushTag: name
294 w@(XML PrintStream traits) endTag
296   w stream nextPut: $>.
297   w
300 w@(XML PrintStream traits) endTag: name
302   w popTag: name.
303   w stream ; '</' ; name.
304   w stream nextPut: $>.
305   w
308 w@(XML PrintStream traits) endEmptyTag: name
310   w popTag: name.
311   w stream ; '/>'.
312   w canonical ifFalse: [w stream nextPut: $\s].
313   w
316 w@(XML PrintStream traits) startElement: name attributes: attribs
318   w canonical ifFalse: [w stream nextPut: $\r].
319   w startTag: name.
320   (attribs keySet as: SortedArray) do: [| :key |
321     w attribute: key value: (attribs at: key)].
322   w
325 w@(XML PrintStream traits) xmlDeclaration: versionString
327   w canonical ifFalse: [
328     w stream ; '<?XML '.
329     w attribute: 'version' value: versionString.
330     w stream ; '?>'].
331   w