Clover coverage report - dom4j - 1.6.1
Coverage timestamp: ma mei 16 2005 14:23:01 GMT+01:00
file stats: LOC: 1.042   Methods: 58
NCLOC: 382   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
SAXReader.java 51,9% 62,6% 58,6% 59,7%
coverage coverage
 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.File;
 11    import java.io.FileInputStream;
 12    import java.io.FileNotFoundException;
 13    import java.io.InputStream;
 14    import java.io.Reader;
 15    import java.io.Serializable;
 16    import java.net.URL;
 17   
 18    import org.dom4j.Document;
 19    import org.dom4j.DocumentException;
 20    import org.dom4j.DocumentFactory;
 21    import org.dom4j.ElementHandler;
 22   
 23    import org.xml.sax.EntityResolver;
 24    import org.xml.sax.ErrorHandler;
 25    import org.xml.sax.InputSource;
 26    import org.xml.sax.SAXException;
 27    import org.xml.sax.SAXParseException;
 28    import org.xml.sax.XMLFilter;
 29    import org.xml.sax.XMLReader;
 30    import org.xml.sax.helpers.DefaultHandler;
 31    import org.xml.sax.helpers.XMLReaderFactory;
 32   
 33    /**
 34    * <p>
 35    * <code>SAXReader</code> creates a DOM4J tree from SAX parsing events.
 36    * </p>
 37    *
 38    * <p>
 39    * The actual SAX parser that is used by this class is configurable so you can
 40    * use your favourite SAX parser if you wish. DOM4J comes configured with its
 41    * own SAX parser so you do not need to worry about configuring the SAX parser.
 42    * </p>
 43    *
 44    * <p>
 45    * To explicitly configure the SAX parser that is used via Java code you can use
 46    * a constructor or use the {@link #setXMLReader(XMLReader)}or {@link
 47    * #setXMLReaderClassName(String)} methods.
 48    * </p>
 49    *
 50    * <p>
 51    * If the parser is not specified explicitly then the standard SAX policy of
 52    * using the <code>org.xml.sax.driver</code> system property is used to
 53    * determine the implementation class of {@link XMLReader}.
 54    * </p>
 55    *
 56    * <p>
 57    * If the <code>org.xml.sax.driver</code> system property is not defined then
 58    * JAXP is used via reflection (so that DOM4J is not explicitly dependent on the
 59    * JAXP classes) to load the JAXP configured SAXParser. If there is any error
 60    * creating a JAXP SAXParser an informational message is output and then the
 61    * default (Aelfred) SAX parser is used instead.
 62    * </p>
 63    *
 64    * <p>
 65    * If you are trying to use JAXP to explicitly set your SAX parser and are
 66    * experiencing problems, you can turn on verbose error reporting by defining
 67    * the system property <code>org.dom4j.verbose</code> to be "true" which will
 68    * output a more detailed description of why JAXP could not find a SAX parser
 69    * </p>
 70    *
 71    * <p>
 72    * For more information on JAXP please go to <a
 73    * href="http://java.sun.com/xml/">Sun's Java &amp; XML site </a>
 74    * </p>
 75    *
 76    * @author <a href="mailto:james.strachan@metastuff.com">James Strachan </a>
 77    * @version $Revision: 1.58 $
 78    */
 79    public class SAXReader {
 80    private static final String SAX_STRING_INTERNING =
 81    "http://xml.org/sax/features/string-interning";
 82    private static final String SAX_NAMESPACE_PREFIXES =
 83    "http://xml.org/sax/features/namespace-prefixes";
 84    private static final String SAX_NAMESPACES =
 85    "http://xml.org/sax/features/namespaces";
 86    private static final String SAX_DECL_HANDLER =
 87    "http://xml.org/sax/properties/declaration-handler";
 88    private static final String SAX_LEXICAL_HANDLER =
 89    "http://xml.org/sax/properties/lexical-handler";
 90    private static final String SAX_LEXICALHANDLER =
 91    "http://xml.org/sax/handlers/LexicalHandler";
 92   
 93    /** <code>DocumentFactory</code> used to create new document objects */
 94    private DocumentFactory factory;
 95   
 96    /** <code>XMLReader</code> used to parse the SAX events */
 97    private XMLReader xmlReader;
 98   
 99    /** Whether validation should occur */
 100    private boolean validating;
 101   
 102    /** DispatchHandler to call when each <code>Element</code> is encountered */
 103    private DispatchHandler dispatchHandler;
 104   
 105    /** ErrorHandler class to use */
 106    private ErrorHandler errorHandler;
 107   
 108    /** The entity resolver */
 109    private EntityResolver entityResolver;
 110   
 111    /** Should element & attribute names and namespace URIs be interned? */
 112    private boolean stringInternEnabled = true;
 113   
 114    /** Should internal DTD declarations be expanded into a List in the DTD */
 115    private boolean includeInternalDTDDeclarations = false;
 116   
 117    /** Should external DTD declarations be expanded into a List in the DTD */
 118    private boolean includeExternalDTDDeclarations = false;
 119   
 120    /** Whether adjacent text nodes should be merged */
 121    private boolean mergeAdjacentText = false;
 122   
 123    /** Holds value of property stripWhitespaceText. */
 124    private boolean stripWhitespaceText = false;
 125   
 126    /** Should we ignore comments */
 127    private boolean ignoreComments = false;
 128   
 129    /** Encoding of InputSource - null means system default encoding */
 130    private String encoding = null;
 131   
 132    // private boolean includeExternalGeneralEntities = false;
 133    // private boolean includeExternalParameterEntities = false;
 134   
 135    /** The SAX filter used to filter SAX events */
 136    private XMLFilter xmlFilter;
 137   
 138  5741 public SAXReader() {
 139    }
 140   
 141  1 public SAXReader(boolean validating) {
 142  1 this.validating = validating;
 143    }
 144   
 145  55 public SAXReader(DocumentFactory factory) {
 146  55 this.factory = factory;
 147    }
 148   
 149  0 public SAXReader(DocumentFactory factory, boolean validating) {
 150  0 this.factory = factory;
 151  0 this.validating = validating;
 152    }
 153   
 154  0 public SAXReader(XMLReader xmlReader) {
 155  0 this.xmlReader = xmlReader;
 156    }
 157   
 158  0 public SAXReader(XMLReader xmlReader, boolean validating) {
 159  0 this.xmlReader = xmlReader;
 160  0 this.validating = validating;
 161    }
 162   
 163  1 public SAXReader(String xmlReaderClassName) throws SAXException {
 164  1 if (xmlReaderClassName != null) {
 165  1 this.xmlReader = XMLReaderFactory
 166    .createXMLReader(xmlReaderClassName);
 167    }
 168    }
 169   
 170  0 public SAXReader(String xmlReaderClassName, boolean validating)
 171    throws SAXException {
 172  0 if (xmlReaderClassName != null) {
 173  0 this.xmlReader = XMLReaderFactory
 174    .createXMLReader(xmlReaderClassName);
 175    }
 176   
 177  0 this.validating = validating;
 178    }
 179   
 180    /**
 181    * Allows a SAX property to be set on the underlying SAX parser. This can be
 182    * useful to set parser-specific properties such as the location of schema
 183    * or DTD resources. Though use this method with caution as it has the
 184    * possibility of breaking the standard behaviour. An alternative to calling
 185    * this method is to correctly configure an XMLReader object instance and
 186    * call the {@link #setXMLReader(XMLReader)}method
 187    *
 188    * @param name
 189    * is the SAX property name
 190    * @param value
 191    * is the value of the SAX property
 192    *
 193    * @throws SAXException
 194    * if the XMLReader could not be created or the property could
 195    * not be changed.
 196    */
 197  0 public void setProperty(String name, Object value) throws SAXException {
 198  0 getXMLReader().setProperty(name, value);
 199    }
 200   
 201    /**
 202    * Sets a SAX feature on the underlying SAX parser. This can be useful to
 203    * set parser-specific features. Though use this method with caution as it
 204    * has the possibility of breaking the standard behaviour. An alternative to
 205    * calling this method is to correctly configure an XMLReader object
 206    * instance and call the {@link #setXMLReader(XMLReader)}method
 207    *
 208    * @param name
 209    * is the SAX feature name
 210    * @param value
 211    * is the value of the SAX feature
 212    *
 213    * @throws SAXException
 214    * if the XMLReader could not be created or the feature could
 215    * not be changed.
 216    */
 217  0 public void setFeature(String name, boolean value) throws SAXException {
 218  0 getXMLReader().setFeature(name, value);
 219    }
 220   
 221    /**
 222    * <p>
 223    * Reads a Document from the given <code>File</code>
 224    * </p>
 225    *
 226    * @param file
 227    * is the <code>File</code> to read from.
 228    *
 229    * @return the newly created Document instance
 230    *
 231    * @throws DocumentException
 232    * if an error occurs during parsing.
 233    */
 234  204 public Document read(File file) throws DocumentException {
 235  204 try {
 236    /*
 237    * We cannot convert the file to an URL because if the filename
 238    * contains '#' characters, there will be problems with the URL in
 239    * the InputSource (because a URL like
 240    * http://myhost.com/index#anchor is treated the same as
 241    * http://myhost.com/index) Thanks to Christian Oetterli
 242    */
 243  204 InputSource source = new InputSource(new FileInputStream(file));
 244  204 if (this.encoding != null) {
 245  0 source.setEncoding(this.encoding);
 246    }
 247  204 String path = file.getAbsolutePath();
 248   
 249  204 if (path != null) {
 250    // Code taken from Ant FileUtils
 251  204 StringBuffer sb = new StringBuffer("file://");
 252   
 253    // add an extra slash for filesystems with drive-specifiers
 254  204 if (!path.startsWith(File.separator)) {
 255  204 sb.append("/");
 256    }
 257   
 258  204 path = path.replace('\\', '/');
 259  204 sb.append(path);
 260   
 261  204 source.setSystemId(sb.toString());
 262    }
 263   
 264  204 return read(source);
 265    } catch (FileNotFoundException e) {
 266  0 throw new DocumentException(e.getMessage(), e);
 267    }
 268    }
 269   
 270    /**
 271    * <p>
 272    * Reads a Document from the given <code>URL</code> using SAX
 273    * </p>
 274    *
 275    * @param url
 276    * <code>URL</code> to read from.
 277    *
 278    * @return the newly created Document instance
 279    *
 280    * @throws DocumentException
 281    * if an error occurs during parsing.
 282    */
 283  0 public Document read(URL url) throws DocumentException {
 284  0 String systemID = url.toExternalForm();
 285   
 286  0 InputSource source = new InputSource(systemID);
 287  0 if (this.encoding != null) {
 288  0 source.setEncoding(this.encoding);
 289    }
 290   
 291  0 return read(source);
 292    }
 293   
 294    /**
 295    * <p>
 296    * Reads a Document from the given URL or filename using SAX.
 297    * </p>
 298    *
 299    * <p>
 300    * If the systemId contains a <code>':'</code> character then it is
 301    * assumed to be a URL otherwise its assumed to be a file name. If you want
 302    * finer grained control over this mechansim then please explicitly pass in
 303    * either a {@link URL}or a {@link File}instance instead of a {@link
 304    * String} to denote the source of the document.
 305    * </p>
 306    *
 307    * @param systemId
 308    * is a URL for a document or a file name.
 309    *
 310    * @return the newly created Document instance
 311    *
 312    * @throws DocumentException
 313    * if an error occurs during parsing.
 314    */
 315  1 public Document read(String systemId) throws DocumentException {
 316  1 InputSource source = new InputSource(systemId);
 317  1 if (this.encoding != null) {
 318  0 source.setEncoding(this.encoding);
 319    }
 320   
 321  1 return read(source);
 322    }
 323   
 324    /**
 325    * <p>
 326    * Reads a Document from the given stream using SAX
 327    * </p>
 328    *
 329    * @param in
 330    * <code>InputStream</code> to read from.
 331    *
 332    * @return the newly created Document instance
 333    *
 334    * @throws DocumentException
 335    * if an error occurs during parsing.
 336    */
 337  1 public Document read(InputStream in) throws DocumentException {
 338  1 InputSource source = new InputSource(in);
 339  1 if (this.encoding != null) {
 340  0 source.setEncoding(this.encoding);
 341    }
 342   
 343  1 return read(source);
 344    }
 345   
 346    /**
 347    * <p>
 348    * Reads a Document from the given <code>Reader</code> using SAX
 349    * </p>
 350    *
 351    * @param reader
 352    * is the reader for the input
 353    *
 354    * @return the newly created Document instance
 355    *
 356    * @throws DocumentException
 357    * if an error occurs during parsing.
 358    */
 359  31 public Document read(Reader reader) throws DocumentException {
 360  31 InputSource source = new InputSource(reader);
 361  31 if (this.encoding != null) {
 362  1 source.setEncoding(this.encoding);
 363    }
 364   
 365  31 return read(source);
 366    }
 367   
 368    /**
 369    * <p>
 370    * Reads a Document from the given stream using SAX
 371    * </p>
 372    *
 373    * @param in
 374    * <code>InputStream</code> to read from.
 375    * @param systemId
 376    * is the URI for the input
 377    *
 378    * @return the newly created Document instance
 379    *
 380    * @throws DocumentException
 381    * if an error occurs during parsing.
 382    */
 383  0 public Document read(InputStream in, String systemId)
 384    throws DocumentException {
 385  0 InputSource source = new InputSource(in);
 386  0 source.setSystemId(systemId);
 387  0 if (this.encoding != null) {
 388  0 source.setEncoding(this.encoding);
 389    }
 390   
 391  0 return read(source);
 392    }
 393   
 394    /**
 395    * <p>
 396    * Reads a Document from the given <code>Reader</code> using SAX
 397    * </p>
 398    *
 399    * @param reader
 400    * is the reader for the input
 401    * @param systemId
 402    * is the URI for the input
 403    *
 404    * @return the newly created Document instance
 405    *
 406    * @throws DocumentException
 407    * if an error occurs during parsing.
 408    */
 409  0 public Document read(Reader reader, String systemId)
 410    throws DocumentException {
 411  0 InputSource source = new InputSource(reader);
 412  0 source.setSystemId(systemId);
 413  0 if (this.encoding != null) {
 414  0 source.setEncoding(this.encoding);
 415    }
 416   
 417  0 return read(source);
 418    }
 419   
 420    /**
 421    * <p>
 422    * Reads a Document from the given <code>InputSource</code> using SAX
 423    * </p>
 424    *
 425    * @param in
 426    * <code>InputSource</code> to read from.
 427    *
 428    * @return the newly created Document instance
 429    *
 430    * @throws DocumentException
 431    * if an error occurs during parsing.
 432    */
 433  5792 public Document read(InputSource in) throws DocumentException {
 434  5792 try {
 435  5792 XMLReader reader = getXMLReader();
 436   
 437  5792 reader = installXMLFilter(reader);
 438   
 439  5792 EntityResolver thatEntityResolver = this.entityResolver;
 440   
 441  5792 if (thatEntityResolver == null) {
 442  5762 thatEntityResolver = createDefaultEntityResolver(in
 443    .getSystemId());
 444  5762 this.entityResolver = thatEntityResolver;
 445    }
 446   
 447  5792 reader.setEntityResolver(thatEntityResolver);
 448   
 449  5792 SAXContentHandler contentHandler = createContentHandler(reader);
 450  5792 contentHandler.setEntityResolver(thatEntityResolver);
 451  5792 contentHandler.setInputSource(in);
 452   
 453  5792 boolean internal = isIncludeInternalDTDDeclarations();
 454  5792 boolean external = isIncludeExternalDTDDeclarations();
 455   
 456  5792 contentHandler.setIncludeInternalDTDDeclarations(internal);
 457  5792 contentHandler.setIncludeExternalDTDDeclarations(external);
 458  5792 contentHandler.setMergeAdjacentText(isMergeAdjacentText());
 459  5792 contentHandler.setStripWhitespaceText(isStripWhitespaceText());
 460  5792 contentHandler.setIgnoreComments(isIgnoreComments());
 461  5792 reader.setContentHandler(contentHandler);
 462   
 463  5792 configureReader(reader, contentHandler);
 464   
 465  5792 reader.parse(in);
 466   
 467  5791 return contentHandler.getDocument();
 468    } catch (Exception e) {
 469  1 if (e instanceof SAXParseException) {
 470    // e.printStackTrace();
 471  0 SAXParseException parseException = (SAXParseException) e;
 472  0 String systemId = parseException.getSystemId();
 473   
 474  0 if (systemId == null) {
 475  0 systemId = "";
 476    }
 477   
 478  0 String message = "Error on line "
 479    + parseException.getLineNumber() + " of document "
 480    + systemId + " : " + parseException.getMessage();
 481   
 482  0 throw new DocumentException(message, e);
 483    } else {
 484  1 throw new DocumentException(e.getMessage(), e);
 485