1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.millscript.millscript.functions;
22
23 import org.millscript.commons.alert.Alert;
24 import org.millscript.commons.alert.alerts.Fault;
25 import org.millscript.commons.util.list.ELinkedList;
26 import org.millscript.commons.xml.alerts.XmlWellFormednessAlert;
27 import org.millscript.commons.xml.api.token.AttListDeclToken;
28 import org.millscript.commons.xml.api.token.CharDataToken;
29 import org.millscript.commons.xml.api.token.CommentToken;
30 import org.millscript.commons.xml.api.token.DTDToken;
31 import org.millscript.commons.xml.api.token.ElementDeclToken;
32 import org.millscript.commons.xml.api.token.EmptyElementToken;
33 import org.millscript.commons.xml.api.token.EndTagToken;
34 import org.millscript.commons.xml.api.token.EntityDeclToken;
35 import org.millscript.commons.xml.api.token.NotationDeclToken;
36 import org.millscript.commons.xml.api.token.PIToken;
37 import org.millscript.commons.xml.api.token.StartTagToken;
38 import org.millscript.commons.xml.api.token.TokenVisitor;
39 import org.millscript.commons.xml.api.token.XmlDeclToken;
40 import org.millscript.millscript.alert.Alerts;
41 import org.millscript.millscript.datatypes.XmlComment;
42 import org.millscript.millscript.datatypes.XmlElement;
43 import org.millscript.millscript.vm.Machine;
44
45 /**
46 * This class provides validation and handling logic for parsing a String which
47 * contains some XML fragments. The XML is considered to match the
48 * <code>content</code> production in the XML specification, e.g. no XML
49 * declaration or DTD.
50 */
51 public class StringToXMLTokenVisitor implements TokenVisitor {
52
53 /**
54 * This body expression for the element.
55 */
56 ELinkedList< Object > body = new ELinkedList< Object >();
57
58 /**
59 * The machine we push our root entities onto.
60 */
61 private final Machine machine;
62
63 /**
64 * The parent token visitor we should return to once this one has finished
65 * what it is supposed to do.
66 */
67 final StringToXMLTokenVisitor parentTokenVisitor;
68
69 /**
70 * The start tag that began the section this token visitor represents.
71 */
72 final StartTagToken startTagToken;
73
74 /**
75 * The function that is controlling the XML parse.
76 */
77 final StringToXMLFunction stringToXMLFunction;
78
79 /**
80 * This class is used when visiting an XML element and it handles the
81 * tokens visited in the elements content.
82 */
83 private class ElementTokenVisitor extends StringToXMLTokenVisitor {
84
85 /**
86 * Constructs a new element token visitor, with the specified
87 * controlling function, parent token visitor and start tag.
88 *
89 * @param stf the controlling function
90 * @param stv the parent token visitor
91 * @param stt the start tag token
92 */
93 public ElementTokenVisitor( final StringToXMLFunction stf, final StringToXMLTokenVisitor stv, final StartTagToken stt ) {
94 super( stf, stv, stt, null );
95 }
96
97 /**
98 * @see org.millscript.millscript.functions.StringToXMLTokenVisitor#pushChildElement(java.lang.Object)
99 */
100 @Override
101 void pushChildElement( final Object o ) {
102 this.body.addLast( o );
103 }
104
105 /**
106 * @see org.millscript.millscript.functions.StringToXMLTokenVisitor#reportAnyErrors()
107 */
108 @Override
109 public void reportAnyErrors() {
110 throw new Alert(
111 "The matching end tag for this start tag appears to be missing"
112 ).decorate( this.startTagToken ).mishap();
113 }
114
115 /**
116 * @see org.millscript.commons.xml.api.token.TokenVisitor#visit(org.millscript.commons.xml.api.token.EndTagToken)
117 */
118 @Override
119 public void visit( final EndTagToken token ) {
120
121 if ( this.startTagToken.getName().equals( token.getName() ) ) {
122
123
124 this.parentTokenVisitor.pushChildElement(
125 new XmlElement(
126 this.startTagToken.getName(),
127 this.startTagToken.getAttributes(),
128 body.toArray()
129 )
130 );
131
132 this.stringToXMLFunction.tokenVisitor = this.parentTokenVisitor;
133 } else {
134 throw new XmlWellFormednessAlert(
135 "Mismatched start/end tags"
136 ).decorate( this.startTagToken ).decorate( token ).mishap();
137 }
138 }
139
140 }
141
142 /**
143 * Constructs a new XML string token visitor, with the specified
144 * controlling function, parent token visitor, start tag and machine.
145 *
146 * @param stf the controlling function
147 * @param stv the parent token visitor
148 * @param stt the start tag token
149 * @param mc the machine to push results to
150 */
151 public StringToXMLTokenVisitor( final StringToXMLFunction stf, final StringToXMLTokenVisitor stv, final StartTagToken stt, final Machine mc ) {
152 this.machine = mc;
153 this.parentTokenVisitor = stv;
154 this.startTagToken = stt;
155 this.stringToXMLFunction = stf;
156 }
157
158 /**
159 * Pushes the expression as part of this elements body.
160 *
161 * @param o the next body element for this element
162 */
163 void pushChildElement( final Object o ) {
164
165 this.machine.pushObject( o );
166 }
167
168 /**
169 * Reports any errors left over after processing the string.
170 */
171 public void reportAnyErrors() {
172
173 }
174
175 /**
176 * @see org.millscript.commons.xml.api.token.TokenVisitor#visit(org.millscript.commons.xml.api.token.AttListDeclToken)
177 */
178 public void visit( final AttListDeclToken token ) {
179
180 throw(
181 Alerts.unimplemented(
182 "Attribute list declarations cannot be compiled at the moment, sorry!"
183 ).decorate( token ).mishap()
184 );
185 }
186
187 /**
188 * @see org.millscript.commons.xml.api.token.TokenVisitor#visit(org.millscript.commons.xml.api.token.CharDataToken)
189 */
190 public void visit( final CharDataToken token ) {
191 if ( token.getCharData().length() == 0 ) {
192
193 throw new Fault(
194 "Appending empty character data"
195 ).mishap();
196 }
197
198 this.pushChildElement(
199 token.getCharData()
200 );
201 }
202
203 /**
204 * @see org.millscript.commons.xml.api.token.TokenVisitor#visit(org.millscript.commons.xml.api.token.CommentToken)
205 */
206 public void visit( final CommentToken token ) {
207 if ( token.getCommentText().length() == 0 ) {
208
209
210 throw new Fault(
211 "Appending empty comment"
212 ).mishap();
213 }
214
215
216 this.pushChildElement(
217 new XmlComment( token.getCommentText() )
218 );
219 }
220
221 /**
222 * @see org.millscript.commons.xml.api.token.TokenVisitor#visit(org.millscript.commons.xml.api.token.DTDToken)
223 */
224 public void visit( final DTDToken token ) {
225 throw(
226 Alerts.unimplemented(
227 "Document type declarations cannot be compiled at the moment, sorry!"
228 ).decorate( token ).mishap()
229 );
230 }
231
232 /**
233 * @see org.millscript.commons.xml.api.token.TokenVisitor#visit(org.millscript.commons.xml.api.token.ElementDeclToken)
234 */
235 public void visit( final ElementDeclToken token ) {
236 throw(
237 Alerts.unimplemented(
238 "Element declarations cannot be compiled at the moment, sorry!"
239 ).decorate( token ).mishap()
240 );
241 }
242
243 /**
244 * @see org.millscript.commons.xml.api.token.TokenVisitor#visit(org.millscript.commons.xml.api.token.EmptyElementToken)
245 */
246 public void visit( final EmptyElementToken token ) {
247
248 this.visit( (StartTagToken) token );
249
250
251 this.stringToXMLFunction.tokenVisitor.visit( (EndTagToken)token );
252 }
253
254 /**
255 * @see org.millscript.commons.xml.api.token.TokenVisitor#visit(org.millscript.commons.xml.api.token.EndTagToken)
256 */
257 public void visit( final EndTagToken token ) {
258 throw new Alert(
259 "The start tag for this element appears to be missing"
260 ).decorate( token ).mishap();
261 }
262
263 /**
264 * @see org.millscript.commons.xml.api.token.TokenVisitor#visit(org.millscript.commons.xml.api.token.EntityDeclToken)
265 */
266 public void visit( final EntityDeclToken token ) {
267 throw(
268 Alerts.unimplemented(
269 "Entity declarations cannot be compiled at the moment, sorry!"
270 ).decorate( token ).mishap()
271 );
272 }
273
274 /**
275 * @see org.millscript.commons.xml.api.token.TokenVisitor#visit(org.millscript.commons.xml.api.token.NotationDeclToken)
276 */
277 public void visit( final NotationDeclToken token ) {
278 throw(
279 Alerts.unimplemented(
280 "Notation declarations cannot be compiled at the moment, sorry!"
281 ).decorate( token ).mishap()
282 );
283 }
284
285 /**
286 * @see org.millscript.commons.xml.api.token.TokenVisitor#visit(org.millscript.commons.xml.api.token.PIToken)
287 */
288 public void visit( final PIToken token ) {
289 throw(
290 Alerts.unimplemented(
291 "Processing instructions cannot be compiled at the moment, sorry!"
292 ).decorate( token ).mishap()
293 );
294 }
295
296 /**
297 * @see org.millscript.commons.xml.api.token.TokenVisitor#visit(org.millscript.commons.xml.api.token.StartTagToken)
298 */
299 public void visit( final StartTagToken token ) {
300
301 this.stringToXMLFunction.tokenVisitor = new ElementTokenVisitor( this.stringToXMLFunction, this.stringToXMLFunction.tokenVisitor, token );
302 }
303
304 /**
305 * @see org.millscript.commons.xml.api.token.TokenVisitor#visit(org.millscript.commons.xml.api.token.XmlDeclToken)
306 */
307 public void visit( final XmlDeclToken token ) {
308
309 }
310
311 }