Clover coverage report - dom4j - 1.6.1
Coverage timestamp: ma mei 16 2005 14:23:01 GMT+01:00

file stats: | LOC: | 541 |  | Methods: | 22
| NCLOC: | 213 |  | Classes: | 1

Source file | Conditionals | Statements | Methods | TOTAL

XPP3Reader.java

34,4%

53,1%

36,4%

46,7%

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;
11 |  | import java.io.CharArrayReader;
12 |  | import java.io.File;
13 |  | import java.io.FileReader;
14 |  | import java.io.IOException;
15 |  | import java.io.InputStream;
16 |  | import java.io.InputStreamReader;
17 |  | import java.io.Reader;
18 |  | import java.net.URL;
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 | 2 | public XPP3Reader() {
56 |  | }
57 |  |
58 | 0 | public XPP3Reader(DocumentFactory factory) {
59 | 0 | 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 | 2 | public Document read(File file) throws DocumentException, IOException,
80 |  | XmlPullParserException {
81 | 2 | String systemID = file.getAbsolutePath();
82 |  |
83 | 2 | return read(new BufferedReader(new FileReader(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 | 0 | public Document read(URL url) throws DocumentException, IOException,
104 |  | XmlPullParserException {
105 | 0 | String systemID = url.toExternalForm();
106 |  |
107 | 0 | 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 | 0 | public Document read(String systemID) throws DocumentException,
136 |  | IOException, XmlPullParserException {
137 | 0 | if (systemID.indexOf(':') >= 0) {
138 |  | // lets assume its a URL
139 | 0 | return read(new URL(systemID));
140 |  | } else {
141 |  | // lets assume that we are given a file name
142 | 0 | return read(new File(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 | 0 | public Document read(InputStream in) throws DocumentException, IOException,
164 |  | XmlPullParserException {
165 | 0 | 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 | 2 | public Document read(Reader reader) throws DocumentException, IOException,
186 |  | XmlPullParserException {
187 | 2 | getXPPParser().setInput(reader);
188 |  |
189 | 2 | 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 | 0 | public Document read(char[] text) throws DocumentException, IOException,
210 |  | XmlPullParserException {
211 | 0 | getXPPParser().setInput(new CharArrayReader(text));
212 |  |
213 | 0 | 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 | 0 | public Document read(InputStream in, String systemID)
236 |  | throws DocumentException, IOException, XmlPullParserException {
237 | 0 | 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 | 2 | public Document read(Reader reader, String systemID)
260 |  | throws DocumentException, IOException, XmlPullParserException {
261 | 2 | Document document = read(reader);
262 | 2 | document.setName(systemID);
263 |  |
264 | 2 | return document;
265 |  | }
266 |  |
267 |  | // Properties
268 |  | // -------------------------------------------------------------------------
269 | 4 | public XmlPullParser getXPPParser() throws XmlPullParserException {
270 | 4 | if (xppParser == null) {
271 | 2 | xppParser = getXPPFactory().newPullParser();
272 |  | }
273 |  |
274 | 4 | return xppParser;
275 |  | }
276 |  |
277 | 2 | public XmlPullParserFactory getXPPFactory() throws XmlPullParserException {
278 | 2 | if (xppFactory == null) {
279 | 2 | xppFactory = XmlPullParserFactory.newInstance();
280 |  | }
281 |  |
282 | 2 | xppFactory.setNamespaceAware(true);
283 |  |
284 | 2 | return xppFactory;
285 |  | }
286 |  |
287 | 0 | public void setXPPFactory(XmlPullParserFactory xPPfactory) {
288 | 0 | this.xppFactory = xPPfactory;
289 |  | }
290 |  |
291 |  | /**
292 |  | * DOCUMENT ME!
293 |  | *
294 |  | * @return the <code>DocumentFactory</code> used to create document
295 |  | * objects
296 |  | */
297 | 2 | public DocumentFactory getDocumentFactory() {
298 | 2 | if (factory == null) {
299 | 2 | factory = DocumentFactory.getInstance();
300 |  | }
301 |  |
302 | 2 | 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 | 0 | public void setDocumentFactory(DocumentFactory documentFactory) {
317 | 0 | 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 | 0 | public void addHandler(String path, ElementHandler handler) {
331 | 0 | 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 | 0 | public void removeHandler(String path) {
342 | 0 | 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 | 0 | public void setDefaultHandler(ElementHandler handler) {
355 | 0 | getDispatchHandler().setDefaultHandler(handler);
356 |  | }
357 |  |
358 |  | // Implementation methods
359 |  | // -------------------------------------------------------------------------
360 | 2 | protected Document parseDocument() throws DocumentException, IOException,
361 |  | XmlPullParserException {
362 | 2 | DocumentFactory df = getDocumentFactory();
363 | 2 | Document document = df.createDocument();
364 | 2 | Element parent = null;
365 | 2 | XmlPullParser pp = getXPPParser();
366 | 2 | pp.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
367 |  |
368 | 2 | while (true) {
369 | 72 | int type = pp.nextToken();
370 |  |
371 | 72 | switch (type) {
372 | 0 | case XmlPullParser.PROCESSING_INSTRUCTION: {
373 | 0 | String text = pp.getText();
374 | 0 | int loc = text.indexOf(" ");
375 |  |
376 | 0 | if (loc >= 0) {
377 | 0 | String target = text.substring(0, loc);
378 | 0 | String txt = text.substring(loc + 1);
379 | 0 | document.addProcessingInstruction(target, txt);
380 |  | } else {
381 | 0 | document.addProcessingInstruction(text, "");
382 |  | }
383 |  |
384 | 0 | break;
385 |  | }
386 |  |
387 | 0 | case XmlPullParser.COMMENT: {
388 | 0 | if (parent != null) {
389 | 0 | parent.addComment(pp.getText());
390 |  | } else {
391 | 0 | document.addComment(pp.getText());
392 |  | }
393 |  |
394 | 0 | break;
395 |  | }
396 |  |
397 | 0 | case XmlPullParser.CDSECT: {
398 | 0 | if (parent != null) {
399 | 0 | parent.addCDATA(pp.getText());
400 |  | } else {
401 | 0 | String msg = "Cannot have text content outside of the "
402 |  | + "root document";
403 | 0 | throw new DocumentException(msg);
404 |  | }
405 |  |
406 | 0 | break;
407 |  | }
408 |  |
409 | 2 | case XmlPullParser.ENTITY_REF:
410 | 2 | break;
411 |  |
412 | 2 | case XmlPullParser.END_DOCUMENT:
413 | 2 | return document;
414 |  |
415 | 16 | case XmlPullParser.START_TAG: {
416 | 16 | QName qname = (pp.getPrefix() == null) ? df.createQName(pp
417 |  | .getName(), pp.getNamespace()) : df.createQName(pp
418 |  | .getName(), pp.getPrefix(), pp.getNamespace());
419 | 16 | Element newElement = df.createElement(qname);
420 | 16 | int nsStart = pp.getNamespaceCount(pp.getDepth() - 1);
421 | 16 | int nsEnd = pp.getNamespaceCount(pp.getDepth());
422 |  |
423 | 16 | for (int i = nsStart; i < nsEnd; i++) {
424 | 0 | if (pp.getNamespacePrefix(i) != null) {
425 | 0 | newElement.addNamespace(pp.getNamespacePrefix(i),
426 |  | pp.getNamespaceUri(i));
427 |  | }
428 |  | }
429 |  |
430 | 16 | for (int i = 0; i < pp.getAttributeCount(); i++) {
431 | 0 | 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 | 0 | newElement.addAttribute(qa, pp.getAttributeValue(i));
437 |  | }
438 |  |
439 | 16 | if (parent != null) {
440 | 14 | parent.add(newElement);
441 |  | } else {
442 | 2 | document.add(newElement);
443 |  | }
444 |  |
445 | 16 | parent = newElement;
446 |  |
447 | 16 | break;
448 |  | }
449 |  |
450 | 16 | case XmlPullParser.END_TAG: {
451 | 16 | if (parent != null) {
452 | 16 | parent = parent.getParent();
453 |  | }
454 |  |
455 | 16 | break;
456 |  | }
457 |  |
458 | 32 | case XmlPullParser.TEXT: {
459 | 32 | String text = pp.getText();
460 |  |
461 | 32 | if (parent != null) {
462 | 32 | parent.addText(text);
463 |  | } else {
464 | 0 | String msg = "Cannot have text content outside of the "
465 |  | + "root document";
466 | 0 | throw new DocumentException(msg);
467 |  | }
468 |  |
469 | 32 | break;
470 |  | }
471 |  |
472 | 4 | default:
473 | 4 | break;
474 |  | }
475 |  | }
476 |  | }
477 |  |
478 | 0 | protected DispatchHandler getDispatchHandler() {
479 | 0 | if (dispatchHandler == null) {
480 | 0 | dispatchHandler = new DispatchHandler();
481 |  | }
482 |  |
483 | 0 | return dispatchHandler;
484 |  | }
485 |  |
486 | 0 | protected void setDispatchHandler(DispatchHandler dispatchHandler) {
487 | 0 | 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 | 0 | protected Reader createReader(InputStream in) throws IOException {
502 | 0 | return new BufferedReader(new InputStreamReader(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 |  | */