KickJava   Java API By Example, From Geeks To Geeks.

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


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.BufferedReader JavaDoc;
11 import java.io.CharArrayReader JavaDoc;
12 import java.io.File JavaDoc;
13 import java.io.FileReader JavaDoc;
14 import java.io.IOException JavaDoc;
15 import java.io.InputStream JavaDoc;
16 import java.io.InputStreamReader JavaDoc;
17 import java.io.Reader JavaDoc;
18 import java.net.URL JavaDoc;
19
20 import org.dom4j.Document;
21 import org.dom4j.DocumentException;
22 import org.dom4j.DocumentFactory;
23 import org.dom4j.Element;
24 import org.dom4j.ElementHandler;
25 import org.dom4j.QName;
26
27 import org.xmlpull.v1.XmlPullParser;
28 import org.xmlpull.v1.XmlPullParserException;
29 import org.xmlpull.v1.XmlPullParserFactory;
30
31 /**
32  * <p>
33  * <code>XPP3Reader</code> is a Reader of DOM4J documents that uses the fast
34  * <a HREF="http://www.extreme.indiana.edu/soap/xpp/">XML Pull Parser 3.x </a>.
35  * It is very fast for use in SOAP style environments.
36  * </p>
37  *
38  * @author <a HREF="mailto:pelle@neubia.com">Pelle Braendgaard </a>
39  * @author <a HREF="mailto:jstrachan@apache.org">James Strachan </a>
40  * @version $Revision: 1.3 $
41  */

42 public class XPP3Reader {
43     /** <code>DocumentFactory</code> used to create new document objects */
44     private DocumentFactory factory;
45
46     /** <code>XmlPullParser</code> used to parse XML */
47     private XmlPullParser xppParser;
48
49     /** <code>XmlPullParser</code> used to parse XML */
50     private XmlPullParserFactory xppFactory;
51
52     /** DispatchHandler to call when each <code>Element</code> is encountered */
53     private DispatchHandler dispatchHandler;
54
55     public XPP3Reader() {
56     }
57
58     public XPP3Reader(DocumentFactory factory) {
59         this.factory = factory;
60     }
61
62     /**
63      * <p>
64      * Reads a Document from the given <code>File</code>
65      * </p>
66      *
67      * @param file
68      * is the <code>File</code> to read from.
69      *
70      * @return the newly created Document instance
71      *
72      * @throws DocumentException
73      * if an error occurs during parsing.
74      * @throws IOException
75      * if a URL could not be made for the given File
76      * @throws XmlPullParserException
77      * DOCUMENT ME!
78      */

79     public Document read(File JavaDoc file) throws DocumentException, IOException JavaDoc,
80             XmlPullParserException {
81         String JavaDoc systemID = file.getAbsolutePath();
82
83         return read(new BufferedReader JavaDoc(new FileReader JavaDoc(file)), systemID);
84     }
85
86     /**
87      * <p>
88      * Reads a Document from the given <code>URL</code>
89      * </p>
90      *
91      * @param url
92      * <code>URL</code> to read from.
93      *
94      * @return the newly created Document instance
95      *
96      * @throws DocumentException
97      * if an error occurs during parsing.
98      * @throws IOException
99      * DOCUMENT ME!
100      * @throws XmlPullParserException
101      * DOCUMENT ME!
102      */

103     public Document read(URL JavaDoc url) throws DocumentException, IOException JavaDoc,
104             XmlPullParserException {
105         String JavaDoc systemID = url.toExternalForm();
106
107         return read(createReader(url.openStream()), systemID);
108     }
109
110     /**
111      * <p>
112      * Reads a Document from the given URL or filename.
113      * </p>
114      *
115      * <p>
116      * If the systemID contains a <code>':'</code> character then it is
117      * assumed to be a URL otherwise its assumed to be a file name. If you want
118      * finer grained control over this mechansim then please explicitly pass in
119      * either a {@link URL}or a {@link File}instance instead of a {@link
120      * String} to denote the source of the document.
121      * </p>
122      *
123      * @param systemID
124      * is a URL for a document or a file name.
125      *
126      * @return the newly created Document instance
127      *
128      * @throws DocumentException
129      * if an error occurs during parsing.
130      * @throws IOException
131      * if a URL could not be made for the given File
132      * @throws XmlPullParserException
133      * DOCUMENT ME!
134      */

135     public Document read(String JavaDoc systemID) throws DocumentException,
136             IOException JavaDoc, XmlPullParserException {
137         if (systemID.indexOf(':') >= 0) {
138             // lets assume its a URL
139
return read(new URL JavaDoc(systemID));
140         } else {
141             // lets assume that we are given a file name
142
return read(new File JavaDoc(systemID));
143         }
144     }
145
146     /**
147      * <p>
148      * Reads a Document from the given stream
149      * </p>
150      *
151      * @param in
152      * <code>InputStream</code> to read from.
153      *
154      * @return the newly created Document instance
155      *
156      * @throws DocumentException
157      * if an error occurs during parsing.
158      * @throws IOException
159      * DOCUMENT ME!
160      * @throws XmlPullParserException
161      * DOCUMENT ME!
162      */

163     public Document read(InputStream JavaDoc in) throws DocumentException, IOException JavaDoc,
164             XmlPullParserException {
165         return read(createReader(in));
166     }
167
168     /**
169      * <p>
170      * Reads a Document from the given <code>Reader</code>
171      * </p>
172      *
173      * @param reader
174      * is the reader for the input
175      *
176      * @return the newly created Document instance
177      *
178      * @throws DocumentException
179      * if an error occurs during parsing.
180      * @throws IOException
181      * DOCUMENT ME!
182      * @throws XmlPullParserException
183      * DOCUMENT ME!
184      */

185     public Document read(Reader JavaDoc reader) throws DocumentException, IOException JavaDoc,
186             XmlPullParserException {
187         getXPPParser().setInput(reader);
188
189         return parseDocument();
190     }
191
192     /**
193      * <p>
194      * Reads a Document from the given array of characters
195      * </p>
196      *
197      * @param text
198      * is the text to parse
199      *
200      * @return the newly created Document instance
201      *
202      * @throws DocumentException
203      * if an error occurs during parsing.
204      * @throws IOException
205      * DOCUMENT ME!
206      * @throws XmlPullParserException
207      * DOCUMENT ME!
208      */

209     public Document read(char[] text) throws DocumentException, IOException JavaDoc,
210             XmlPullParserException {
211         getXPPParser().setInput(new CharArrayReader JavaDoc(text));
212
213         return parseDocument();
214     }
215
216     /**
217      * <p>
218      * Reads a Document from the given stream
219      * </p>
220      *
221      * @param in
222      * <code>InputStream</code> to read from.
223      * @param systemID
224      * is the URI for the input
225      *
226      * @return the newly created Document instance
227      *
228      * @throws DocumentException
229      * if an error occurs during parsing.
230      * @throws IOException
231      * DOCUMENT ME!
232      * @throws XmlPullParserException
233      * DOCUMENT ME!
234      */

235     public Document read(InputStream JavaDoc in, String JavaDoc systemID)
236             throws DocumentException, IOException JavaDoc, XmlPullParserException {
237         return read(createReader(in), systemID);
238     }
239
240     /**
241      * <p>
242      * Reads a Document from the given <code>Reader</code>
243      * </p>
244      *
245      * @param reader
246      * is the reader for the input
247      * @param systemID
248      * is the URI for the input
249      *
250      * @return the newly created Document instance
251      *
252      * @throws DocumentException
253      * if an error occurs during parsing.
254      * @throws IOException
255      * DOCUMENT ME!
256      * @throws XmlPullParserException
257      * DOCUMENT ME!
258      */

259     public Document read(Reader JavaDoc reader, String JavaDoc systemID)
260             throws DocumentException, IOException JavaDoc, XmlPullParserException {
261         Document document = read(reader);
262         document.setName(systemID);
263
264         return document;
265     }
266
267     // Properties
268
// -------------------------------------------------------------------------
269
public XmlPullParser getXPPParser() throws XmlPullParserException {
270         if (xppParser == null) {
271             xppParser = getXPPFactory().newPullParser();
272         }
273
274         return xppParser;
275     }
276
277     public XmlPullParserFactory getXPPFactory() throws XmlPullParserException {
278         if (xppFactory == null) {
279             xppFactory = XmlPullParserFactory.newInstance();
280         }
281
282         xppFactory.setNamespaceAware(true);
283
284         return xppFactory;
285     }
286
287     public void setXPPFactory(XmlPullParserFactory xPPfactory) {
288         this.xppFactory = xPPfactory;
289     }
290
291     /**
292      * DOCUMENT ME!
293      *
294      * @return the <code>DocumentFactory</code> used to create document
295      * objects
296      */

297     public DocumentFactory getDocumentFactory() {
298         if (factory == null) {
299             factory = DocumentFactory.getInstance();
300         }
301
302         return factory;
303     }
304
305     /**
306      * <p>
307      * This sets the <code>DocumentFactory</code> used to create new
308      * documents. This method allows the building of custom DOM4J tree objects
309      * to be implemented easily using a custom derivation of
310      * {@link DocumentFactory}
311      * </p>
312      *
313      * @param documentFactory
314      * <code>DocumentFactory</code> used to create DOM4J objects
315      */

316     public void setDocumentFactory(DocumentFactory documentFactory) {
317         this.factory = documentFactory;
318     }
319
320     /**
321      * Adds the <code>ElementHandler</code> to be called when the specified
322      * path is encounted.
323      *
324      * @param path
325      * is the path to be handled
326      * @param handler
327      * is the <code>ElementHandler</code> to be called by the event
328      * based processor.
329      */

330     public void addHandler(String JavaDoc path, ElementHandler handler) {
331         getDispatchHandler().addHandler(path, handler);
332     }
333
334     /**
335      * Removes the <code>ElementHandler</code> from the event based processor,
336      * for the specified path.
337      *
338      * @param path
339      * is the path to remove the <code>ElementHandler</code> for.
340      */

341     public void removeHandler(String JavaDoc path) {
342         getDispatchHandler().removeHandler(path);
343     }
344
345     /**
346      * When multiple <code>ElementHandler</code> instances have been
347      * registered, this will set a default <code>ElementHandler</code> to be
348      * called for any path which does <b>NOT </b> have a handler registered.
349      *
350      * @param handler
351      * is the <code>ElementHandler</code> to be called by the event
352      * based processor.
353      */

354     public void setDefaultHandler(ElementHandler handler) {
355         getDispatchHandler().setDefaultHandler(handler);
356     }
357
358     // Implementation methods
359
// -------------------------------------------------------------------------
360
protected Document parseDocument() throws DocumentException, IOException JavaDoc,
361             XmlPullParserException {
362         DocumentFactory df = getDocumentFactory();
363         Document document = df.createDocument();
364         Element parent = null;
365         XmlPullParser pp = getXPPParser();
366         pp.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
367
368         while (true) {
369             int type = pp.nextToken();
370
371             switch (type) {
372                 case XmlPullParser.PROCESSING_INSTRUCTION: {
373                     String JavaDoc text = pp.getText();
374                     int loc = text.indexOf(" ");
375
376                     if (loc >= 0) {
377                         String JavaDoc target = text.substring(0, loc);
378                         String JavaDoc txt = text.substring(loc + 1);
379                         document.addProcessingInstruction(target, txt);
380                     } else {
381                         document.addProcessingInstruction(text, "");
382                     }
383
384                     break;
385                 }
386
387                 case XmlPullParser.COMMENT: {
388                     if (parent != null) {
389                         parent.addComment(pp.getText());
390                     } else {
391                         document.addComment(pp.getText());
392                     }
393
394                     break;
395                 }
396
397                 case XmlPullParser.CDSECT: {
398                     if (parent != null) {
399                         parent.addCDATA(pp.getText());
400                     } else {
401                         String JavaDoc msg = "Cannot have text content outside of the "
402                                 + "root document";
403                         throw new DocumentException(msg);
404                     }
405
406                     break;
407                 }
408
409                 case XmlPullParser.ENTITY_REF:
410                     break;
411
412                 case XmlPullParser.END_DOCUMENT:
413                     return document;
414
415                 case XmlPullParser.START_TAG: {
416                     QName qname = (pp.getPrefix() == null) ? df.createQName(pp
417                             .getName(), pp.getNamespace()) : df.createQName(pp
418                             .getName(), pp.getPrefix(), pp.getNamespace());
419                     Element newElement = df.createElement(qname);
420                     int nsStart = pp.getNamespaceCount(pp.getDepth() - 1);
421                     int nsEnd = pp.getNamespaceCount(pp.getDepth());
422
423                     for (int i = nsStart; i < nsEnd; i++) {
424                         if (pp.getNamespacePrefix(i) != null) {
425                             newElement.addNamespace(pp.getNamespacePrefix(i),
426                                     pp.getNamespaceUri(i));
427                         }
428                     }
429
430                     for (int i = 0; i < pp.getAttributeCount(); i++) {
431                         QName qa = (pp.getAttributePrefix(i) == null) ? df
432                                 .createQName(pp.getAttributeName(i)) : df
433                                 .createQName(pp.getAttributeName(i), pp
434                                         .getAttributePrefix(i), pp
435                                         .getAttributeNamespace(i));
436                         newElement.addAttribute(qa, pp.getAttributeValue(i));
437                     }
438
439                     if (parent != null) {
440                         parent.add(newElement);
441                     } else {
442                         document.add(newElement);
443                     }
444
445                     parent = newElement;
446
447                     break;
448                 }
449
450                 case XmlPullParser.END_TAG: {
451                     if (parent != null) {
452                         parent = parent.getParent();
453                     }
454
455                     break;
456                 }
457
458                 case XmlPullParser.TEXT: {
459                     String JavaDoc text = pp.getText();
460
461                     if (parent != null) {
462                         parent.addText(text);
463                     } else {
464                         String JavaDoc msg = "Cannot have text content outside of the "
465                                 + "root document";
466                         throw new DocumentException(msg);
467                     }
468
469                     break;
470                 }
471
472                 default:
473                     break;
474             }
475         }
476     }
477
478     protected DispatchHandler getDispatchHandler() {
479         if (dispatchHandler == null) {
480             dispatchHandler = new DispatchHandler();
481         }
482
483         return dispatchHandler;
484     }
485
486     protected void setDispatchHandler(DispatchHandler dispatchHandler) {
487         this.dispatchHandler = dispatchHandler;
488     }
489
490     /**
491      * Factory method to create a Reader from the given InputStream.
492      *
493      * @param in
494      * DOCUMENT ME!
495      *
496      * @return DOCUMENT ME!
497      *
498      * @throws IOException
499      * DOCUMENT ME!
500      */

501     protected Reader JavaDoc createReader(InputStream JavaDoc in) throws IOException JavaDoc {
502         return new BufferedReader JavaDoc(new InputStreamReader JavaDoc(in));
503     }
504 }
505
506 /*
507  * Redistribution and use of this software and associated documentation
508  * ("Software"), with or without modification, are permitted provided that the
509  * following conditions are met:
510  *
511  * 1. Redistributions of source code must retain copyright statements and
512  * notices. Redistributions must also contain a copy of this document.
513  *
514  * 2. Redistributions in binary form must reproduce the above copyright notice,
515  * this list of conditions and the following disclaimer in the documentation
516  * and/or other materials provided with the distribution.
517  *
518  * 3. The name "DOM4J" must not be used to endorse or promote products derived
519  * from this Software without prior written permission of MetaStuff, Ltd. For
520  * written permission, please contact dom4j-info@metastuff.com.
521  *
522  * 4. Products derived from this Software may not be called "DOM4J" nor may
523  * "DOM4J" appear in their names without prior written permission of MetaStuff,
524  * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
525  *
526  * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
527  *
528  * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
529  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
530  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
531  * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
532  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
533  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
534  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
535  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
536  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
537  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
538  * POSSIBILITY OF SUCH DAMAGE.
539  *
540  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
541  */

542
Popular Tags