KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > n3 > nanoxml > StdXMLParser


1 /* StdXMLParser.java NanoXML/Java
2  *
3  * $Revision: 1422 $
4  * $Date: 2006-03-21 19:14:56 +0100 (Tue, 21 Mar 2006) $
5  * $Name$
6  *
7  * This file is part of NanoXML 2 for Java.
8  * Copyright (C) 2001 Marc De Scheemaecker, All Rights Reserved.
9  *
10  * This software is provided 'as-is', without any express or implied warranty.
11  * In no event will the authors be held liable for any damages arising from the
12  * use of this software.
13  *
14  * Permission is granted to anyone to use this software for any purpose,
15  * including commercial applications, and to alter it and redistribute it
16  * freely, subject to the following restrictions:
17  *
18  * 1. The origin of this software must not be misrepresented; you must not
19  * claim that you wrote the original software. If you use this software in
20  * a product, an acknowledgment in the product documentation would be
21  * appreciated but is not required.
22  *
23  * 2. Altered source versions must be plainly marked as such, and must not be
24  * misrepresented as being the original software.
25  *
26  * 3. This notice may not be removed or altered from any source distribution.
27  */

28
29 package net.n3.nanoxml;
30
31 import java.io.Reader JavaDoc;
32 import java.util.Enumeration JavaDoc;
33 import java.util.Properties JavaDoc;
34
35 /**
36  * StdXMLParser is the core parser of NanoXML.
37  *
38  * @author Marc De Scheemaecker
39  * @version $Name$, $Revision: 1422 $
40  */

41 public class StdXMLParser implements IXMLParser
42 {
43
44     /**
45      * Delimiter for a processing instructions.
46      */

47     private static final char[] END_OF_PI = { '>', '?'};
48
49     /**
50      * Delimiter for CDATA sections.
51      */

52     private static final char[] END_OF_CDATA = { '>', ']', ']'};
53
54     /**
55      * Delimiter for PCDATA elements.
56      */

57     private static final char[] END_OF_PCDATA = { '<'};
58
59     /**
60      * The builder which creates the logical structure of the XML data.
61      */

62     private IXMLBuilder builder;
63
64     /**
65      * The reader from which the parser retrieves its data.
66      */

67     private IXMLReader reader;
68
69     /**
70      * The entity resolver.
71      */

72     private IXMLEntityResolver entityResolver;
73
74     /**
75      * The validator that will process entity references and validate the XML data.
76      */

77     private IXMLValidator validator;
78
79     /**
80      * Creates a new parser.
81      */

82     public StdXMLParser()
83     {
84         this.builder = null;
85         this.validator = null;
86         this.reader = null;
87         this.entityResolver = new XMLEntityResolver();
88     }
89
90     /**
91      * Cleans up the object when it's destroyed.
92      */

93     protected void finalize() throws Throwable JavaDoc
94     {
95         this.builder = null;
96         this.reader = null;
97         this.entityResolver = null;
98         this.validator = null;
99         super.finalize();
100     }
101
102     /**
103      * Sets the builder which creates the logical structure of the XML data.
104      *
105      * @param builder the non-null builder
106      */

107     public void setBuilder(IXMLBuilder builder)
108     {
109         this.builder = builder;
110     }
111
112     /**
113      * Returns the builder which creates the logical structure of the XML data.
114      *
115      * @return the builder
116      */

117     public IXMLBuilder getBuilder()
118     {
119         return this.builder;
120     }
121
122     /**
123      * Sets the validator that validates the XML data.
124      *
125      * @param validator the non-null validator
126      */

127     public void setValidator(IXMLValidator validator)
128     {
129         this.validator = validator;
130     }
131
132     /**
133      * Returns the validator that validates the XML data.
134      *
135      * @return the validator
136      */

137     public IXMLValidator getValidator()
138     {
139         return this.validator;
140     }
141
142     /**
143      * Sets the entity resolver.
144      *
145      * @param resolver the non-null resolver
146      */

147     public void setResolver(IXMLEntityResolver resolver)
148     {
149         this.entityResolver = resolver;
150     }
151
152     /**
153      * Returns the entity resolver.
154      *
155      * @return the non-null resolver
156      */

157     public IXMLEntityResolver getResolver()
158     {
159         return this.entityResolver;
160     }
161
162     /**
163      * Sets the reader from which the parser retrieves its data.
164      *
165      * @param reader the reader
166      */

167     public void setReader(IXMLReader reader)
168     {
169         this.reader = reader;
170     }
171
172     /**
173      * Returns the reader from which the parser retrieves its data.
174      *
175      * @return the reader
176      */

177     public IXMLReader getReader()
178     {
179         return this.reader;
180     }
181
182     /**
183      * Parses the data and lets the builder create the logical data structure.
184      *
185      * @return the logical structure built by the builder
186      *
187      * @throws net.n3.nanoxml.XMLException if an error occurred reading or parsing the data
188      */

189     public Object JavaDoc parse() throws XMLException
190     {
191         try
192         {
193             this.builder.startBuilding(this.reader.getSystemID(), this.reader.getLineNr());
194             this.scanData();
195             return this.builder.getResult();
196         }
197         catch (XMLException e)
198         {
199             throw e;
200         }
201         catch (Exception JavaDoc e)
202         {
203             throw new XMLException(e);
204         }
205     }
206
207     /**
208      * Scans the XML data for elements.
209      *
210      * @throws java.lang.Exception if something went wrong
211      */

212     protected void scanData() throws Exception JavaDoc
213     {
214         while ((!this.reader.atEOF()) && (this.builder.getResult() == null))
215         {
216             char ch = XMLUtil.read(this.reader, null, '&', this.entityResolver);
217
218             switch (ch)
219             {
220             case '<':
221                 this.scanSomeTag(false /* don't allow CDATA */);
222                 break;
223
224             case ' ':
225             case '\t':
226             case '\r':
227             case '\n':
228                 // skip whitespace
229
break;
230
231             default:
232                 XMLUtil.errorInvalidInput(reader.getSystemID(), reader.getLineNr(), "`" + ch
233                         + "' (0x" + Integer.toHexString((int) ch) + ')');
234             }
235         }
236     }
237
238     /**
239      * Scans an XML tag.
240      *
241      * @param allowCDATA true if CDATA sections are allowed at this point
242      *
243      * @throws java.lang.Exception if something went wrong
244      */

245     protected void scanSomeTag(boolean allowCDATA) throws Exception JavaDoc
246     {
247         char ch = XMLUtil.read(this.reader, null, '&', this.entityResolver);
248
249         switch (ch)
250         {
251         case '?':
252             this.processPI();
253             break;
254
255         case '!':
256             this.processSpecialTag(allowCDATA);
257             break;
258
259         default:
260             this.reader.unread(ch);
261             this.processElement();
262         }
263     }
264
265     /**
266      * Processes a "processing instruction".
267      *
268      * @throws java.lang.Exception if something went wrong
269      */

270     protected void processPI() throws Exception JavaDoc
271     {
272         XMLUtil.skipWhitespace(this.reader, '&', null, null);
273         String JavaDoc target = XMLUtil.scanIdentifier(this.reader, '&', this.entityResolver);
274         XMLUtil.skipWhitespace(this.reader, '&', null, null);
275         Reader JavaDoc reader = new ContentReader(this.reader, this.entityResolver, '&',
276                 StdXMLParser.END_OF_PI, true, "");
277
278         if (!"xml".equalsIgnoreCase(target))
279         {
280             this.builder.newProcessingInstruction(target, reader);
281         }
282
283         reader.close();
284     }
285
286     /**
287      * Processes a tag that starts with a bang (&lt;&#x21;&#x2e;&#x2e;&#x2e;&gt;).
288      *
289      * @param allowCDATA true if CDATA sections are allowed at this point
290      *
291      * @throws java.lang.Exception if something went wrong
292      */

293     protected void processSpecialTag(boolean allowCDATA) throws Exception JavaDoc
294     {
295         char ch = XMLUtil.read(this.reader, null, '&', this.entityResolver);
296
297         switch (ch)
298         {
299         case '[':
300             if (allowCDATA)
301             {
302                 this.processCDATA();
303             }
304             else
305             {
306                 XMLUtil.skipTag(this.reader, '&', this.entityResolver);
307             }
308
309             return;
310
311         case 'D':
312             this.processDocType();
313             return;
314
315         case '-':
316             XMLUtil.skipComment(this.reader, this.entityResolver);
317         }
318     }
319
320     /**
321      * Processes a CDATA section.
322      *
323      * @throws java.lang.Exception if something went wrong
324      */

325     protected void processCDATA() throws Exception JavaDoc
326     {
327         if (!XMLUtil.checkLiteral(this.reader, '&', this.entityResolver, "CDATA["))
328         {
329             XMLUtil.skipTag(this.reader, '&', this.entityResolver);
330             return;
331         }
332
333         this.validator.PCDataAdded(this.reader.getSystemID(), this.reader.getLineNr());
334         Reader JavaDoc reader = new ContentReader(this.reader, this.entityResolver, '&',
335                 StdXMLParser.END_OF_CDATA, true, "");
336
337         this.builder.addPCData(reader, this.reader.getSystemID(), this.reader.getLineNr());
338         reader.close();
339     }
340
341     /**
342      * Processes a document type declaration.
343      *
344      * @throws java.lang.Exception if an error occurred reading or parsing the data
345      */

346     protected void processDocType() throws Exception JavaDoc
347     {
348         if (!XMLUtil.checkLiteral(this.reader, '&', this.entityResolver, "OCTYPE"))
349         {
350             XMLUtil.skipTag(this.reader, '&', this.entityResolver);
351             return;
352         }
353
354         XMLUtil.skipWhitespace(this.reader, '&', null, null);
355         String JavaDoc systemID = null;
356         StringBuffer JavaDoc publicID = new StringBuffer JavaDoc();
357         XMLUtil.skipWhitespace(this.reader, '&', null, null);
358         char ch = XMLUtil.read(this.reader, null, '&', this.entityResolver);
359
360         if (ch == 'P')
361         {
362             systemID = XMLUtil.scanPublicID(publicID, reader, '&', this.entityResolver);
363             XMLUtil.skipWhitespace(this.reader, '&', null, null);
364             ch = XMLUtil.read(this.reader, null, '&', this.entityResolver);
365         }
366         else if (ch == 'S')
367         {
368             systemID = XMLUtil.scanSystemID(reader, '&', this.entityResolver);
369             XMLUtil.skipWhitespace(this.reader, '&', null, null);
370             ch = XMLUtil.read(this.reader, null, '&', this.entityResolver);
371         }
372
373         if (ch == '[')
374         {
375             this.validator.parseDTD(publicID.toString(), this.reader, this.entityResolver, false);
376             XMLUtil.skipWhitespace(this.reader, '&', null, null);
377             ch = XMLUtil.read(this.reader, null, '&', this.entityResolver);
378         }
379
380         if (ch != '>')
381         {
382             XMLUtil.errorExpectedInput(reader.getSystemID(), reader.getLineNr(), "`>'");
383         }
384
385         if (systemID != null)
386         {
387             Reader JavaDoc reader = this.reader.openStream(publicID.toString(), systemID);
388             this.reader.startNewStream(reader);
389             this.reader.setSystemID(systemID);
390             this.reader.setPublicID(publicID.toString());
391             this.validator.parseDTD(publicID.toString(), this.reader, this.entityResolver, true);
392         }
393     }
394
395     /**
396      * Processes a regular element.
397      *
398      * @throws java.lang.Exception if something went wrong
399      */

400     protected void processElement() throws Exception JavaDoc
401     {
402         String JavaDoc name = XMLUtil.scanIdentifier(this.reader, '&', this.entityResolver);
403         XMLUtil.skipWhitespace(this.reader, '&', null, null);
404         String JavaDoc prefix = null;
405         int colonIndex = name.indexOf(':');
406
407         if (colonIndex > 0)
408         {
409             prefix = name.substring(0, colonIndex);
410             name = name.substring(colonIndex + 1);
411         }
412
413         this.validator.elementStarted(name, prefix, null, this.reader.getSystemID(), this.reader
414                 .getLineNr());
415         this.builder.startElement(name, prefix, null, this.reader.getSystemID(), this.reader
416                 .getLineNr());
417         char ch;
418
419         for (;;)
420         {
421             ch = XMLUtil.read(this.reader, null, '&', this.entityResolver);
422
423             if ((ch == '/') || (ch == '>'))
424             {
425                 break;
426             }
427
428             this.reader.unread(ch);
429             this.processAttribute();
430             XMLUtil.skipWhitespace(this.reader, '&', null, null);
431         }
432
433         Properties JavaDoc extraAttributes = new Properties JavaDoc();
434         this.validator.elementAttributesProcessed(name, prefix, null, extraAttributes, this.reader
435                 .getSystemID(), this.reader.getLineNr());
436         Enumeration JavaDoc enumeration = extraAttributes.keys();
437
438         while (enumeration.hasMoreElements())
439         {
440             String JavaDoc key = (String JavaDoc) enumeration.nextElement();
441             String JavaDoc value = extraAttributes.getProperty(key);
442             String JavaDoc attPrefix = null;
443             colonIndex = key.indexOf(':');
444
445             if (colonIndex > 0)
446             {
447                 attPrefix = key.substring(0, colonIndex);
448                 key = key.substring(colonIndex + 1);
449             }
450
451             this.builder.addAttribute(key, attPrefix, null, value, "CDATA");
452         }
453
454         this.builder.elementAttributesProcessed(name, prefix, null);
455
456         if (ch == '/')
457         {
458             if (XMLUtil.read(this.reader, null, '&', this.entityResolver) != '>')
459             {
460                 XMLUtil.errorExpectedInput(reader.getSystemID(), reader.getLineNr(), "`>'");
461             }
462
463             this.validator.elementEnded(name, prefix, null, this.reader.getSystemID(), this.reader
464                     .getLineNr());
465             this.builder.endElement(name, prefix, null);
466             return;
467         }
468
469         StringBuffer JavaDoc whitespaceBuffer = new StringBuffer JavaDoc(16);
470
471         for (;;)
472         {
473             whitespaceBuffer.setLength(0);
474             boolean fromEntity[] = new boolean[1];
475             XMLUtil.skipWhitespace(this.reader, '&', whitespaceBuffer, fromEntity);
476             ch = XMLUtil.read(this.reader, null, '&', this.entityResolver);
477
478             if ((ch == '<') && (!fromEntity[0]))
479             {
480                 ch = reader.read();
481
482                 if (ch == '/')
483                 {
484                     XMLUtil.skipWhitespace(this.reader, '&', null, null);
485                     String JavaDoc str = XMLUtil.scanIdentifier(this.reader, '&', this.entityResolver);
486
487                     if (!str.equals(name))
488                     {
489                         XMLUtil.errorWrongClosingTag(reader.getSystemID(), reader.getLineNr(),
490                                 name, str);
491                     }
492
493                     XMLUtil.skipWhitespace(this.reader, '&', null, null);
494
495                     if (XMLUtil.read(this.reader, null, '&', this.entityResolver) != '>')
496                     {
497                         XMLUtil.errorClosingTagNotEmpty(reader.getSystemID(), reader.getLineNr());
498                     }
499
500                     this.validator.elementEnded(name, prefix, null, this.reader.getSystemID(),
501                             this.reader.getLineNr());
502                     this.builder.endElement(name, prefix, null);
503                     break;
504                 }
505                 else
506                 {
507                     this.reader.unread(ch);
508                     this.scanSomeTag(true /* CDATA allowed */);
509                 }
510             }
511             else
512             {
513                 this.validator.PCDataAdded(this.reader.getSystemID(), this.reader.getLineNr());
514                 this.reader.unread(ch);
515                 Reader JavaDoc reader = new ContentReader(this.reader, this.entityResolver, '&',
516                         StdXMLParser.END_OF_PCDATA, false, whitespaceBuffer.toString());
517                 this.builder.addPCData(reader, this.reader.getSystemID(), this.reader.getLineNr());
518                 reader.close();
519                 this.reader.unread('<');
520             }
521         }
522     }
523
524     /**
525      * Processes an attribute of an element.
526      *
527      * @throws java.lang.Exception if something went wrong
528      */

529     protected void processAttribute() throws Exception JavaDoc
530     {
531         String JavaDoc key = XMLUtil.scanIdentifier(this.reader, '&', this.entityResolver);
532         XMLUtil.skipWhitespace(this.reader, '&', null, null);
533
534         if (XMLUtil.read(this.reader, null, '&', this.entityResolver) != '=')
535         {
536             XMLUtil.errorExpectedInput(reader.getSystemID(), reader.getLineNr(), "`='");
537         }
538
539         String JavaDoc value = XMLUtil.scanString(this.reader, '&', true, this.entityResolver);
540         this.validator.attributeAdded(key, null, null, value, this.reader.getSystemID(),
541                 this.reader.getLineNr());
542         this.builder.addAttribute(key, null, null, value, "CDATA");
543     }
544
545 }
546
Popular Tags