KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > dom4j > io > STAXEventReader


1 /*
2  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
3  *
4  * This software is open source.
5  * See the bottom of this file for the licence.
6  */

7
8 package org.dom4j.io;
9
10 import java.io.InputStream JavaDoc;
11 import java.io.Reader JavaDoc;
12 import java.util.Iterator JavaDoc;
13
14 import javax.xml.namespace.QName JavaDoc;
15 import javax.xml.stream.XMLEventReader;
16 import javax.xml.stream.XMLInputFactory;
17 import javax.xml.stream.XMLStreamConstants;
18 import javax.xml.stream.XMLStreamException;
19 import javax.xml.stream.events.Attribute;
20 import javax.xml.stream.events.Characters;
21 import javax.xml.stream.events.Comment;
22 import javax.xml.stream.events.EndElement;
23 import javax.xml.stream.events.EntityReference;
24 import javax.xml.stream.events.Namespace;
25 import javax.xml.stream.events.ProcessingInstruction;
26 import javax.xml.stream.events.StartDocument;
27 import javax.xml.stream.events.StartElement;
28 import javax.xml.stream.events.XMLEvent;
29
30 import org.dom4j.CharacterData;
31 import org.dom4j.Document;
32 import org.dom4j.DocumentFactory;
33 import org.dom4j.Element;
34 import org.dom4j.Entity;
35 import org.dom4j.Node;
36
37 /**
38  * Reads a DOM4J {@link Document}, as well as other {@link Node}s, from a StAX
39  * {@link XMLEventReader}.
40  *
41  * @author Christian Niles
42  */

43 public class STAXEventReader {
44     /** Reference to the DocumentFactory used to build DOM4J nodes. */
45     private DocumentFactory factory;
46
47     /** A StAX input factory, used to construct streams from IO streams. */
48     private XMLInputFactory inputFactory = XMLInputFactory.newInstance();
49
50     /**
51      * Constructs a default <code>STAXEventReader</code> instance with a
52      * default {@link DocumentFactory}.
53      */

54     public STAXEventReader() {
55         this.factory = DocumentFactory.getInstance();
56     }
57
58     /**
59      * Constructs a <code>STAXEventReader</code> instance that uses the
60      * specified {@link DocumentFactory}to construct DOM4J {@link Node}s.
61      *
62      * @param factory
63      * The DocumentFactory to use when constructing DOM4J nodes, or
64      * <code>null</code> if a default should be used.
65      */

66     public STAXEventReader(DocumentFactory factory) {
67         if (factory != null) {
68             this.factory = factory;
69         } else {
70             this.factory = DocumentFactory.getInstance();
71         }
72     }
73
74     /**
75      * Sets the DocumentFactory to be used when constructing DOM4J nodes.
76      *
77      * @param documentFactory
78      * The DocumentFactory to use when constructing DOM4J nodes, or
79      * <code>null</code> if a default should be used.
80      */

81     public void setDocumentFactory(DocumentFactory documentFactory) {
82         if (documentFactory != null) {
83             this.factory = documentFactory;
84         } else {
85             this.factory = DocumentFactory.getInstance();
86         }
87     }
88
89     /**
90      * Constructs a StAX event stream from the provided I/O stream and reads a
91      * DOM4J document from it.
92      *
93      * @param is
94      * The I/O stream from which the Document will be read.
95      *
96      * @return The Document that was read from the stream.
97      *
98      * @throws XMLStreamException
99      * If an error occurs reading content from the stream.
100      */

101     public Document readDocument(InputStream JavaDoc is) throws XMLStreamException {
102         return readDocument(is, null);
103     }
104
105     /**
106      * Constructs a StAX event stream from the provided I/O character stream and
107      * reads a DOM4J document from it.
108      *
109      * @param reader
110      * The character stream from which the Document will be read.
111      *
112      * @return The Document that was read from the stream.
113      *
114      * @throws XMLStreamException
115      * If an error occurs reading content from the stream.
116      */

117     public Document readDocument(Reader JavaDoc reader) throws XMLStreamException {
118         return readDocument(reader, null);
119     }
120
121     /**
122      * Constructs a StAX event stream from the provided I/O stream and reads a
123      * DOM4J document from it.
124      *
125      * @param is
126      * The I/O stream from which the Document will be read.
127      * @param systemId
128      * A system id used to resolve entities.
129      *
130      * @return The Document that was read from the stream.
131      *
132      * @throws XMLStreamException
133      * If an error occurs reading content from the stream.
134      */

135     public Document readDocument(InputStream JavaDoc is, String JavaDoc systemId)
136             throws XMLStreamException {
137         XMLEventReader eventReader = inputFactory.createXMLEventReader(
138                 systemId, is);
139
140         try {
141             return readDocument(eventReader);
142         } finally {
143             eventReader.close();
144         }
145     }
146
147     /**
148      * Constructs a StAX event stream from the provided I/O character stream and
149      * reads a DOM4J document from it.
150      *
151      * @param reader
152      * The character stream from which the Document will be read.
153      * @param systemId
154      * A system id used to resolve entities.
155      *
156      * @return The Document that was read from the stream.
157      *
158      * @throws XMLStreamException
159      * If an error occurs reading content from the stream.
160      */

161     public Document readDocument(Reader JavaDoc reader, String JavaDoc systemId)
162             throws XMLStreamException {
163         XMLEventReader eventReader = inputFactory.createXMLEventReader(
164                 systemId, reader);
165
166         try {
167             return readDocument(eventReader);
168         } finally {
169             eventReader.close();
170         }
171     }
172
173     /**
174      * Reads a {@link Node}from the event stream. If the next event is a
175      * {@link StartElement}, all events until the closing {@link EndElement}
176      * will be read, and the resulting nodes will be added to the returned
177      * {@link Element}.
178      *
179      * <p>
180      * <strong>Pre-Conditions </strong>: The stream must be positioned before an
181      * event other than an <code>EndElement</code>,<code>EndDocument</code>,
182      * or any DTD-related events, which are not currently supported.
183      * </p>
184      *
185      * @param reader
186      * The reader from which events will be read.
187      *
188      * @return A DOM4J {@link Node}constructed from the read events.
189      *
190      * @throws XMLStreamException
191      * If an error occurs reading from the stream, or the stream was
192      * positioned before an unsupported event.
193      */

194     public Node readNode(XMLEventReader reader) throws XMLStreamException {
195         XMLEvent event = reader.peek();
196
197         if (event.isStartElement()) {
198             return readElement(reader);
199         } else if (event.isCharacters()) {
200             return readCharacters(reader);
201         } else if (event.isStartDocument()) {
202             return readDocument(reader);
203         } else if (event.isProcessingInstruction()) {
204             return readProcessingInstruction(reader);
205         } else if (event.isEntityReference()) {
206             return readEntityReference(reader);
207         } else if (event.isAttribute()) {
208             return readAttribute(reader);
209         } else if (event.isNamespace()) {
210             return readNamespace(reader);
211         } else {
212             throw new XMLStreamException("Unsupported event: " + event);
213         }
214     }
215
216     /**
217      * Reads a DOM4J {@link Document}from the provided stream. The stream
218      * should be positioned at the start of a document, or before a {@link
219      * StartElement} event.
220      *
221      * @param reader
222      * The event stream from which to read the {@link Document}.
223      *
224      * @return The {@link Document}that was read from the stream.
225      *
226      * @throws XMLStreamException
227      * If an error occurs reading events from the stream.
228      */

229     public Document readDocument(XMLEventReader reader)
230             throws XMLStreamException {
231         Document doc = null;
232
233         while (reader.hasNext()) {
234             XMLEvent nextEvent = reader.peek();
235             int type = nextEvent.getEventType();
236
237             switch (type) {
238                 case XMLStreamConstants.START_DOCUMENT:
239
240                     StartDocument event = (StartDocument) reader.nextEvent();
241
242                     if (doc == null) {
243                         // create document
244
if (event.encodingSet()) {
245                             String JavaDoc encodingScheme = event
246                                     .getCharacterEncodingScheme();
247                             doc = factory.createDocument(encodingScheme);
248                         } else {
249                             doc = factory.createDocument();
250                         }
251                     } else {
252                         // duplicate or misplaced xml declaration
253
String JavaDoc msg = "Unexpected StartDocument event";
254                         throw new XMLStreamException(msg, event.getLocation());
255                     }
256
257                     break;
258
259                 case XMLStreamConstants.END_DOCUMENT:
260                 case XMLStreamConstants.SPACE:
261                 case XMLStreamConstants.CHARACTERS:
262
263                     // skip end document and space outside the root element
264
reader.nextEvent();
265
266                     break;
267
268                 default:
269
270                     if (doc == null) {
271                         // create document
272
doc = factory.createDocument();
273                     }
274
275                     Node n = readNode(reader);
276                     doc.add(n);
277             }
278         }
279
280         return doc;
281     }
282
283     /**
284      * Reads a DOM4J Element from the provided event stream. The stream must be
285      * positioned before an {@link StartElement}event. In addition to the
286      * initial start event, all events up to and including the closing {@link
287      * EndElement} will be read, and included with the returned element.
288      *
289      * @param eventReader
290      * The event stream from which to read the Element.
291      *
292      * @return The Element that was read from the stream.
293      *
294      * @throws XMLStreamException
295      * If an error occured reading events from the stream, or the
296      * stream was not positioned before a {@linkStartElement}event.
297      */

298     public Element readElement(XMLEventReader eventReader)
299             throws XMLStreamException {
300         XMLEvent event = eventReader.peek();
301
302         if (event.isStartElement()) {
303             // advance the reader and get the StartElement event
304
StartElement startTag = eventReader.nextEvent().asStartElement();
305             Element elem = createElement(startTag);
306
307             // read element content
308
while (true) {
309                 if (!eventReader.hasNext()) {
310                     String JavaDoc msg = "Unexpected end of stream while reading"
311                             + " element content";
312                     throw new XMLStreamException(msg);
313                 }
314
315                 XMLEvent nextEvent = eventReader.peek();
316
317                 if (nextEvent.isEndElement()) {
318                     EndElement endElem = eventReader.nextEvent().asEndElement();
319
320                     if (!endElem.getName().equals(startTag.getName())) {
321                         throw new XMLStreamException("Expected "
322                                 + startTag.getName() + " end-tag, but found"
323                                 + endElem.getName());
324                     }
325
326                     break;
327                 }
328
329                 Node child = readNode(eventReader);
330                 elem.add(child);
331             }
332
333             return elem;
334         } else {
335             throw new XMLStreamException("Expected Element event, found: "
336                     + event);
337         }
338     }
339
340     /**
341      * Constructs a DOM4J Attribute from the provided event stream. The stream
342      * must be positioned before an {@link Attribute}event.
343      *
344      * @param reader
345      * The event stream from which to read the Attribute.
346      *
347      * @return The Attribute that was read from the stream.
348      *
349      * @throws XMLStreamException
350      * If an error occured reading events from the stream, or the
351      * stream was not positioned before an {@linkAttribute}event.
352      */

353     public org.dom4j.Attribute readAttribute(XMLEventReader reader)
354             throws XMLStreamException {
355         XMLEvent event = reader.peek();
356
357         if (event.isAttribute()) {
358             Attribute attr = (Attribute) reader.nextEvent();
359
360             return createAttribute(null, attr);
361         } else {
362             throw new XMLStreamException("Expected Attribute event, found: "
363                     + event);
364         }
365     }
366
367     /**
368      * Constructs a DOM4J Namespace from the provided event stream. The stream
369      * must be positioned before a {@link Namespace}event.
370      *
371      * @param reader
372      * The event stream from which to read the Namespace.
373      *
374      * @return The Namespace that was read from the stream.
375      *
376      * @throws XMLStreamException
377      * If an error occured reading events from the stream, or the
378      * stream was not positioned before a {@linkNamespace}event.
379      */

380     public org.dom4j.Namespace readNamespace(XMLEventReader reader)
381             throws XMLStreamException {
382         XMLEvent event = reader.peek();
383
384         if (event.isNamespace()) {
385             Namespace ns = (Namespace) reader.nextEvent();
386
387             return createNamespace(ns);
388         } else {
389             throw new XMLStreamException("Expected Namespace event, found: "
390                     + event);
391         }
392     }
393
394     /**
395      * Constructs a DOM4J Text or CDATA section from the provided event stream.
396      * The stream must be positioned before a {@link Characters}event.
397      *
398      * @param reader
399      * The event stream from which to read the Text or CDATA.
400      *
401      * @return The Text or CDATA that was read from the stream.
402      *
403      * @throws XMLStreamException
404      * If an error occured reading events from the stream, or the
405      * stream was not positioned before a {@linkCharacters}event.
406      */

407     public CharacterData readCharacters(XMLEventReader reader)
408             throws XMLStreamException {
409         XMLEvent event = reader.peek();
410
411         if (event.isCharacters()) {
412             Characters characters = reader.nextEvent().asCharacters();
413
414             return createCharacterData(characters);
415         } else {
416             throw new XMLStreamException("Expected Characters event, found: "
417                     + event);
418         }
419     }
420
421     /**
422      * Constructs a DOM4J Comment from the provided event stream. The stream
423      * must be positioned before a {@link Comment}event.
424      *
425      * @param reader
426      * The event stream from which to read the Comment.
427      *
428      * @return The Comment that was read from the stream.
429      *
430      * @throws XMLStreamException
431      * If an error occured reading events from the stream, or the
432      * stream was not positioned before a {@linkComment}event.
433      */

434     public org.dom4j.Comment readComment(XMLEventReader reader)
435             throws XMLStreamException {
436         XMLEvent event = reader.peek();
437
438         if (event instanceof Comment) {
439             return createComment((Comment) reader.nextEvent());
440         } else {
441             throw new XMLStreamException("Expected Comment event, found: "
442                     + event);
443         }
444     }
445
446     /**
447      * Constructs a DOM4J Entity from the provided event stream. The stream must
448      * be positioned before an {@link EntityReference}event.
449      *
450      * @param reader
451      * The event stream from which to read the {@link
452      * EntityReference}.
453      *
454      * @return The {@link org.dom4j.Entity}that was read from the stream.
455      *
456      * @throws XMLStreamException
457      * If an error occured reading events from the stream, or the
458      * stream was not positioned before an {@linkEntityReference}
459      * event.
460      */

461     public Entity readEntityReference(XMLEventReader reader)
462             throws XMLStreamException {
463         XMLEvent event = reader.peek();
464
465         if (event.isEntityReference()) {
466             EntityReference entityRef = (EntityReference) reader.nextEvent();
467
468             return createEntity(entityRef);
469         } else {
470             throw new XMLStreamException("Expected EntityRef event, found: "
471                     + event);
472         }
473     }
474
475     /**
476      * Constructs a DOM4J ProcessingInstruction from the provided event stream.
477      * The stream must be positioned before a {@link ProcessingInstruction}
478      * event.
479      *
480      * @param reader
481      * The event stream from which to read the ProcessingInstruction.
482      *
483      * @return The ProcessingInstruction that was read from the stream.
484      *
485      * @throws XMLStreamException
486      * If an error occured reading events from the stream, or the
487      * stream was not positioned before a {@link
488      * ProcessingInstruction} event.
489      */

490     public org.dom4j.ProcessingInstruction readProcessingInstruction(
491             XMLEventReader reader) throws XMLStreamException {
492         XMLEvent event = reader.peek();
493
494         if (event.isProcessingInstruction()) {
495             ProcessingInstruction pi = (ProcessingInstruction) reader
496                     .nextEvent();
497
498             return createProcessingInstruction(pi);
499         } else {
500             throw new XMLStreamException("Expected PI event, found: " + event);
501         }
502     }
503
504     /**
505      * Constructs a new DOM4J Element from the provided StartElement event. All
506      * attributes and namespaces will be added to the returned element.
507      *
508      * @param startEvent
509      * The StartElement event from which to construct the new DOM4J
510      * Element.
511      *
512      * @return The Element constructed from the provided StartElement event.
513      */

514     public Element createElement(StartElement startEvent) {
515         QName JavaDoc qname = startEvent.getName();
516         org.dom4j.QName elemName = createQName(qname);
517
518         Element elem = factory.createElement(elemName);
519
520         // create attributes
521
for (Iterator JavaDoc i = startEvent.getAttributes(); i.hasNext();) {
522             Attribute attr = (Attribute) i.next();
523             elem.addAttribute(createQName(attr.getName()), attr.getValue());
524         }
525
526         // create namespaces
527
for (Iterator JavaDoc i = startEvent.getNamespaces(); i.hasNext();) {
528             Namespace ns = (Namespace) i.next();
529             elem.addNamespace(ns.getPrefix(), ns.getNamespaceURI());
530         }
531
532         return elem;
533     }
534
535     /**
536      * Constructs a new DOM4J Attribute from the provided StAX Attribute event.
537      *
538      * @param elem
539      * DOCUMENT ME!
540      * @param attr
541      * The Attribute event from which to construct the new DOM4J
542      * Attribute.
543      *
544      * @return The Attribute constructed from the provided Attribute event.
545      */

546     public org.dom4j.Attribute createAttribute(Element elem, Attribute attr) {
547         return factory.createAttribute(elem, createQName(attr.getName()), attr
548                 .getValue());
549     }
550
551     /**
552      * Constructs a new DOM4J Namespace from the provided StAX Namespace event.
553      *
554      * @param ns
555      * The Namespace event from which to construct the new DOM4J
556      * Namespace.
557      *
558      * @return The Namespace constructed from the provided Namespace event.
559      */

560     public org.dom4j.Namespace createNamespace(Namespace ns) {
561         return factory.createNamespace(ns.getPrefix(), ns.getNamespaceURI());
562     }
563
564     /**
565      * Constructs a new DOM4J Text or CDATA object from the provided Characters
566      * event.
567      *
568      * @param characters
569      * The Characters event from which to construct the new DOM4J
570      * Text or CDATA object.
571      *
572      * @return The Text or CDATA object constructed from the provided Characters
573      * event.
574      */

575     public CharacterData createCharacterData(Characters characters) {
576         String JavaDoc data = characters.getData();
577
578         if (characters.isCData()) {
579             return factory.createCDATA(data);
580         } else {
581             return factory.createText(data);
582         }
583     }
584
585     /**
586      * Constructs a new DOM4J Comment from the provided StAX Comment event.
587      *
588      * @param comment
589      * The Comment event from which to construct the new DOM4J
590      * Comment.
591      *
592      * @return The Comment constructed from the provided Comment event.
593      */

594     public org.dom4j.Comment createComment(Comment comment) {
595         return factory.createComment(comment.getText());
596     }
597
598     /**
599      * Constructs a new DOM4J Entity from the provided StAX EntityReference
600      * event.
601      *
602      * @param entityRef
603      * The EntityReference event from which to construct the new
604      * DOM4J Entity.
605      *
606      * @return The Entity constructed from the provided EntityReference event.
607      */

608     public org.dom4j.Entity createEntity(EntityReference entityRef) {
609         return factory.createEntity(entityRef.getName(), entityRef
610                 .getDeclaration().getReplacementText());
611     }
612
613     /**
614      * Constructs a new DOM4J ProcessingInstruction from the provided StAX
615      * ProcessingInstruction event.
616      *
617      * @param pi
618      * The ProcessingInstruction event from which to construct the
619      * new DOM4J ProcessingInstruction.
620      *
621      * @return The ProcessingInstruction constructed from the provided
622      * ProcessingInstruction event.
623      */

624     public org.dom4j.ProcessingInstruction createProcessingInstruction(
625             ProcessingInstruction pi) {
626         return factory
627                 .createProcessingInstruction(pi.getTarget(), pi.getData());
628     }
629
630     /**
631      * Constructs a new DOM4J QName from the provided JAXP QName.
632      *
633      * @param qname
634      * The JAXP QName from which to create a DOM4J QName.
635      *
636      * @return The newly constructed DOM4J QName.
637      */

638     public org.dom4j.QName createQName(QName JavaDoc qname) {
639         return factory.createQName(qname.getLocalPart(), qname.getPrefix(),
640                 qname.getNamespaceURI());
641     }
642 }
643
644 /*
645  * Redistribution and use of this software and associated documentation
646  * ("Software"), with or without modification, are permitted provided that the
647  * following conditions are met:
648  *
649  * 1. Redistributions of source code must retain copyright statements and
650  * notices. Redistributions must also contain a copy of this document.
651  *
652  * 2. Redistributions in binary form must reproduce the above copyright notice,
653  * this list of conditions and the following disclaimer in the documentation
654  * and/or other materials provided with the distribution.
655  *
656  * 3. The name "DOM4J" must not be used to endorse or promote products derived
657  * from this Software without prior written permission of MetaStuff, Ltd. For
658  * written permission, please contact dom4j-info@metastuff.com.
659  *
660  * 4. Products derived from this Software may not be called "DOM4J" nor may
661  * "DOM4J" appear in their names without prior written permission of MetaStuff,
662  * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
663  *
664  * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
665  *
666  * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
667  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
668  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
669  * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
670  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
671  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
672  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
673  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
674  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
675  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
676  * POSSIBILITY OF SUCH DAMAGE.
677  *
678  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
679  */

680
Popular Tags