Coverage Report - org.jdom2.input.SAXBuilder
 
Classes in this File Line Coverage Branch Coverage Complexity
SAXBuilder
91%
183/201
89%
61/68
2.235
 
 1  
 /*--
 2  
 
 3  
  Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
 4  
  All rights reserved.
 5  
 
 6  
  Redistribution and use in source and binary forms, with or without
 7  
  modification, are permitted provided that the following conditions
 8  
  are met:
 9  
 
 10  
  1. Redistributions of source code must retain the above copyright
 11  
     notice, this list of conditions, and the following disclaimer.
 12  
 
 13  
  2. Redistributions in binary form must reproduce the above copyright
 14  
     notice, this list of conditions, and the disclaimer that follows
 15  
     these conditions in the documentation and/or other materials
 16  
     provided with the distribution.
 17  
 
 18  
  3. The name "JDOM" must not be used to endorse or promote products
 19  
     derived from this software without prior written permission.  For
 20  
     written permission, please contact <request_AT_jdom_DOT_org>.
 21  
 
 22  
  4. Products derived from this software may not be called "JDOM", nor
 23  
     may "JDOM" appear in their name, without prior written permission
 24  
     from the JDOM Project Management <request_AT_jdom_DOT_org>.
 25  
 
 26  
  In addition, we request (but do not require) that you include in the
 27  
  end-user documentation provided with the redistribution and/or in the
 28  
  software itself an acknowledgement equivalent to the following:
 29  
      "This product includes software developed by the
 30  
       JDOM Project (http://www.jdom.org/)."
 31  
  Alternatively, the acknowledgment may be graphical using the logos
 32  
  available at http://www.jdom.org/images/logos.
 33  
 
 34  
  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 35  
  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 36  
  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 37  
  DISCLAIMED.  IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
 38  
  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 39  
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 40  
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 41  
  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 42  
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 43  
  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 44  
  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 45  
  SUCH DAMAGE.
 46  
 
 47  
  This software consists of voluntary contributions made by many
 48  
  individuals on behalf of the JDOM Project and was originally
 49  
  created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
 50  
  Brett McLaughlin <brett_AT_jdom_DOT_org>.  For more information
 51  
  on the JDOM Project, please see <http://www.jdom.org/>.
 52  
 
 53  
  */
 54  
 
 55  
 package org.jdom2.input;
 56  
 
 57  
 import static org.jdom2.JDOMConstants.SAX_FEATURE_EXTERNAL_ENT;
 58  
 import static org.jdom2.JDOMConstants.SAX_PROPERTY_DECLARATION_HANDLER;
 59  
 import static org.jdom2.JDOMConstants.SAX_PROPERTY_LEXICAL_HANDLER;
 60  
 import static org.jdom2.JDOMConstants.SAX_PROPERTY_LEXICAL_HANDLER_ALT;
 61  
 
 62  
 import java.io.File;
 63  
 import java.io.IOException;
 64  
 import java.io.InputStream;
 65  
 import java.io.Reader;
 66  
 import java.net.MalformedURLException;
 67  
 import java.net.URL;
 68  
 import java.util.HashMap;
 69  
 import java.util.Map;
 70  
 
 71  
 import org.xml.sax.DTDHandler;
 72  
 import org.xml.sax.EntityResolver;
 73  
 import org.xml.sax.ErrorHandler;
 74  
 import org.xml.sax.InputSource;
 75  
 import org.xml.sax.SAXException;
 76  
 import org.xml.sax.SAXNotRecognizedException;
 77  
 import org.xml.sax.SAXNotSupportedException;
 78  
 import org.xml.sax.XMLFilter;
 79  
 import org.xml.sax.XMLReader;
 80  
 
 81  
 import org.jdom2.DefaultJDOMFactory;
 82  
 import org.jdom2.DocType;
 83  
 import org.jdom2.Document;
 84  
 import org.jdom2.EntityRef;
 85  
 import org.jdom2.JDOMException;
 86  
 import org.jdom2.JDOMFactory;
 87  
 import org.jdom2.Verifier;
 88  
 import org.jdom2.input.sax.BuilderErrorHandler;
 89  
 import org.jdom2.input.sax.DefaultSAXHandlerFactory;
 90  
 import org.jdom2.input.sax.SAXBuilderEngine;
 91  
 import org.jdom2.input.sax.SAXEngine;
 92  
 import org.jdom2.input.sax.SAXHandler;
 93  
 import org.jdom2.input.sax.SAXHandlerFactory;
 94  
 import org.jdom2.input.sax.XMLReaderJDOMFactory;
 95  
 import org.jdom2.input.sax.XMLReaderSAX2Factory;
 96  
 import org.jdom2.input.sax.XMLReaders;
 97  
 
 98  
 /**
 99  
  * Builds a JDOM Document using a SAX parser.
 100  
  * <p>
 101  
  * SAXbuilder uses a third-party SAX parser (chosen by JAXP by default, or you
 102  
  * can configure it manually) to handle the parsing duties and uses an instance
 103  
  * of a SAXHandler to listen to the SAX events in order to construct a document
 104  
  * with JDOM content using a JDOMFactory. Information about SAX can be found at
 105  
  * <a href="http://www.saxproject.org">http://www.saxproject.org</a>.
 106  
  * <p>
 107  
  * For a complete description of how SAXBuilder is used, and how to customise
 108  
  * the process you should look at the {@link org.jdom2.input.sax} package
 109  
  * documentation.
 110  
  * <p>
 111  
  * JDOM users needing to customise the SAX parsing process have traditionally
 112  
  * sub-classed this SAXBuilder class. In JDOM2 this should never be necessary.
 113  
  * Please read the full documentation of this class, {@link SAXHandler},
 114  
  * {@link SAXHandlerFactory}, {@link JDOMFactory}, and the package documentation
 115  
  * for {@link org.jdom2.input.sax} before overriding this class. Future versions
 116  
  * of JDOM2 may make this class 'final'. I you feel you have a good reason to
 117  
  * subclass SAXBuilder please mention it on <a
 118  
  * href="http://www.jdom.org/involved/lists.html">jdom-interest</a> mailing list
 119  
  * so that SAXBuilder can be extended or adapted to handle your use-case.
 120  
  * <p>
 121  
  * Neither SAXBuilder nor anything derived from SAXBuilder is thread-safe. You
 122  
  * must ensure that SAXBuilder is used in a single thread, or that sufficient
 123  
  * locking is in place to ensure that SAXBuilder is not concurrently accessed.
 124  
  * See the special note on {@link #buildEngine()}. 
 125  
  * <p>
 126  
  * Known issues:
 127  
  * <ul>
 128  
  * <li>Relative paths for a {@link DocType} or {@link EntityRef} may be
 129  
  * converted by the SAX parser into absolute paths.
 130  
  * <li>SAX does not recognise whitespace character content outside the root
 131  
  * element (nor does JDOM) so any formatting outside the root Element will be
 132  
  * lost.
 133  
  * </ul>
 134  
  * 
 135  
  * @see org.jdom2.input.sax
 136  
  * @author Jason Hunter
 137  
  * @author Brett McLaughlin
 138  
  * @author Dan Schaffer
 139  
  * @author Philip Nelson
 140  
  * @author Alex Rosen
 141  
  * @author Rolf Lear
 142  
  */
 143  
 public class SAXBuilder implements SAXEngine {
 144  
 
 145  
         /** Default source of SAXHandlers */
 146  1
         private static final SAXHandlerFactory DEFAULTSAXHANDLERFAC =
 147  
                         new DefaultSAXHandlerFactory();
 148  
 
 149  
         /** Default source of JDOM Content */
 150  1
         private static final JDOMFactory DEFAULTJDOMFAC = new DefaultJDOMFactory();
 151  
 
 152  
         /*
 153  
          * ====================================================================
 154  
          */
 155  
 
 156  
         /**
 157  
          * The XMLReader pillar of SAXBuilder
 158  
          */
 159  145
         private XMLReaderJDOMFactory readerfac = null;
 160  
 
 161  
         /**
 162  
          * The SAXHandler pillar of SAXBuilder
 163  
          */
 164  145
         private SAXHandlerFactory handlerfac = null;
 165  
 
 166  
         /**
 167  
          * The JDOMFactory pillar for creating new JDOM objects
 168  
          */
 169  145
         private JDOMFactory jdomfac = null;
 170  
 
 171  
         /*
 172  
          * ========================================================================
 173  
          * Configuration settings for SAX parsing.
 174  
          * ========================================================================
 175  
          */
 176  
 
 177  
         /** User-specified features to be set on the SAX parser */
 178  145
         private final HashMap<String, Boolean> features = new HashMap<String, Boolean>(5);
 179  
 
 180  
         /** User-specified properties to be set on the SAX parser */
 181  145
         private final HashMap<String, Object> properties = new HashMap<String, Object>(5);
 182  
 
 183  
         /** ErrorHandler class to use */
 184  145
         private ErrorHandler saxErrorHandler = null;
 185  
 
 186  
         /** EntityResolver class to use */
 187  145
         private EntityResolver saxEntityResolver = null;
 188  
 
 189  
         /** DTDHandler class to use */
 190  145
         private DTDHandler saxDTDHandler = null;
 191  
 
 192  
         /** XMLFilter instance to use */
 193  145
         private XMLFilter saxXMLFilter = null;
 194  
 
 195  
         /** Whether expansion of entities should occur */
 196  145
         private boolean expand = true;
 197  
 
 198  
         /** Whether to ignore ignorable whitespace */
 199  145
         private boolean ignoringWhite = false;
 200  
 
 201  
         /** Whether to ignore all whitespace content */
 202  145
         private boolean ignoringBoundaryWhite = false;
 203  
 
 204  
         /** Whether parser reuse is allowed. */
 205  145
         private boolean reuseParser = true;
 206  
 
 207  
         /** The current SAX parser, if parser reuse has been activated. */
 208  145
         private SAXEngine engine = null;
 209  
 
 210  
         /**
 211  
          * Creates a new JAXP-based SAXBuilder. The underlying parser will not
 212  
          * validate.
 213  
          * 
 214  
          * @see SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory,
 215  
          *      JDOMFactory)
 216  
          * @see XMLReaders#NONVALIDATING
 217  
          * @see DefaultSAXHandlerFactory
 218  
          * @see DefaultJDOMFactory
 219  
          */
 220  
         public SAXBuilder() {
 221  89
                 this(null, null, null);
 222  89
         }
 223  
 
 224  
         /**
 225  
          * Creates a new JAXP-based SAXBuilder. The underlying parser will validate
 226  
          * (using DTD) or not according to the given parameter. If you want Schema
 227  
          * validation then use SAXBuilder(XMLReaders.XSDVALIDATOR)
 228  
          * 
 229  
          * @see SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory,
 230  
          *      JDOMFactory)
 231  
          * @see XMLReaders#NONVALIDATING
 232  
          * @see XMLReaders#DTDVALIDATING
 233  
          * @see DefaultSAXHandlerFactory
 234  
          * @see DefaultJDOMFactory
 235  
          * @see org.jdom2.input.sax for important details on SAXBuilder
 236  
          * @param validate
 237  
          *        <code>boolean</code> indicating if DTD validation should occur.
 238  
          * @deprecated use {@link SAXBuilder#SAXBuilder(XMLReaderJDOMFactory)} with 
 239  
          *              either {@link XMLReaders#DTDVALIDATING}
 240  
          *              or {@link XMLReaders#NONVALIDATING} 
 241  
          */
 242  
         @Deprecated
 243  
         public SAXBuilder(final boolean validate) {
 244  26
                 this(validate
 245  
                                 ? XMLReaders.DTDVALIDATING
 246  
                                 : XMLReaders.NONVALIDATING,
 247  
                                 null, null);
 248  26
         }
 249  
 
 250  
         /**
 251  
          * Creates a new SAXBuilder using the specified SAX parser. The underlying
 252  
          * parser will not validate.
 253  
          * 
 254  
          * @see SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory,
 255  
          *      JDOMFactory)
 256  
          * @see XMLReaderSAX2Factory
 257  
          * @see DefaultSAXHandlerFactory
 258  
          * @see DefaultJDOMFactory
 259  
          * @see org.jdom2.input.sax for important details on SAXBuilder
 260  
          * @param saxDriverClass
 261  
          *        <code>String</code> name of SAX Driver to use for parsing.
 262  
          * @deprecated use {@link SAXBuilder#SAXBuilder(XMLReaderJDOMFactory)} with 
 263  
          *        {@link XMLReaderSAX2Factory#XMLReaderSAX2Factory(boolean, String)}
 264  
          */
 265  
         @Deprecated
 266  
         public SAXBuilder(final String saxDriverClass) {
 267  3
                 this(saxDriverClass, false);
 268  3
         }
 269  
 
 270  
         /**
 271  
          * Creates a new SAXBuilder using the specified SAX2.0 parser source. The
 272  
          * underlying parser will validate or not according to the given parameter.
 273  
          * 
 274  
          * @see SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory,
 275  
          *      JDOMFactory)
 276  
          * @see XMLReaderSAX2Factory
 277  
          * @see DefaultSAXHandlerFactory
 278  
          * @see DefaultJDOMFactory
 279  
          * @see org.jdom2.input.sax for important details on SAXBuilder
 280  
          * @param saxDriverClass
 281  
          *        <code>String</code> name of SAX Driver to use for parsing.
 282  
          * @param validate
 283  
          *        <code>boolean</code> indicating if validation should occur.
 284  
          * @deprecated use {@link SAXBuilder#SAXBuilder(XMLReaderJDOMFactory)} with 
 285  
          *        {@link XMLReaderSAX2Factory#XMLReaderSAX2Factory(boolean, String)}
 286  
          */
 287  
         @Deprecated
 288  
         public SAXBuilder(final String saxDriverClass, final boolean validate) {
 289  5
                 this(new XMLReaderSAX2Factory(validate, saxDriverClass), null, null);
 290  5
         }
 291  
 
 292  
         /**
 293  
          * Creates a new SAXBuilder with the specified XMLReaderJDOMFactory.
 294  
          * <p>
 295  
          * 
 296  
          * @see SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory,
 297  
          *      JDOMFactory)
 298  
          * @see XMLReaderJDOMFactory
 299  
          * @see XMLReaders#NONVALIDATING
 300  
          * @see DefaultSAXHandlerFactory
 301  
          * @see DefaultJDOMFactory
 302  
          * @see org.jdom2.input.sax for important details on SAXBuilder
 303  
          * @param readersouce
 304  
          *        the {@link XMLReaderJDOMFactory} that supplies XMLReaders. If the
 305  
          *        value is null then a Non-Validating JAXP-based SAX2.0 parser will
 306  
          *        be used.
 307  
          */
 308  
         public SAXBuilder(final XMLReaderJDOMFactory readersouce) {
 309  25
                 this(readersouce, null, null);
 310  25
         }
 311  
 
 312  
         /**
 313  
          * Creates a new SAXBuilder. This is the base constructor for all other
 314  
          * SAXBuilder constructors: they all find a way to create a
 315  
          * JDOMXMLReaderFactory and then call this constructor with that factory,
 316  
          * and the {@link DefaultSAXHandlerFactory} and {@link DefaultJDOMFactory}.
 317  
          * <p>
 318  
          * 
 319  
          * @see XMLReaderJDOMFactory
 320  
          * @see XMLReaders#NONVALIDATING
 321  
          * @see SAXHandlerFactory
 322  
          * @see DefaultSAXHandlerFactory
 323  
          * @see JDOMFactory
 324  
          * @see DefaultJDOMFactory
 325  
          * @see org.jdom2.input.sax for important details on SAXBuilder
 326  
          * @param xmlreaderfactory
 327  
          *        a {@link XMLReaderJDOMFactory} that creates XMLReaders. Specify
 328  
          *        null for the default.
 329  
          * @param handlerfactory
 330  
          *        a {@link SAXHandlerFactory} that creates SAXHandlers Specify null
 331  
          *        for the default.
 332  
          * @param jdomfactory
 333  
          *        a {@link JDOMFactory} that creates JDOM Content. Specify null for
 334  
          *        the default.
 335  
          */
 336  
         public SAXBuilder(final XMLReaderJDOMFactory xmlreaderfactory, final SAXHandlerFactory handlerfactory,
 337  145
                         final JDOMFactory jdomfactory) {
 338  145
                 this.readerfac = xmlreaderfactory == null
 339  
                                 ? XMLReaders.NONVALIDATING
 340  
                                 : xmlreaderfactory;
 341  145
                 this.handlerfac = handlerfactory == null
 342  
                                 ? DEFAULTSAXHANDLERFAC
 343  
                                 : handlerfactory;
 344  145
                 this.jdomfac = jdomfactory == null
 345  
                                 ? DEFAULTJDOMFAC
 346  
                                 : jdomfactory;
 347  145
         }
 348  
 
 349  
         /**
 350  
          * Returns the driver class assigned in the constructor, or null if none.
 351  
          * The driver class is only available if a SAX2 source was specified. This
 352  
          * method is available for backward-compatibility with JDOM 1.x
 353  
          * 
 354  
          * @return the driver class assigned in the constructor
 355  
          * @deprecated as the driver class is only available in limited situations
 356  
          *             and anyway it had to be supplied in a constructor as either a
 357  
          *             direct value or as an {@link XMLReaderSAX2Factory} instance.
 358  
          */
 359  
         @Deprecated
 360  
         public String getDriverClass() {
 361  14
                 if (readerfac instanceof XMLReaderSAX2Factory) {
 362  6
                         return ((XMLReaderSAX2Factory) readerfac).getDriverClassName();
 363  
                 }
 364  8
                 return null;
 365  
         }
 366  
 
 367  
         /**
 368  
          * Returns the current {@link org.jdom2.JDOMFactory} in use.
 369  
          * 
 370  
          * @return the factory in use
 371  
          * @deprecated as it is replaced by {@link #getJDOMFactory()}
 372  
          */
 373  
         @Deprecated
 374  
         public JDOMFactory getFactory() {
 375  1
                 return getJDOMFactory();
 376  
         }
 377  
 
 378  
         /**
 379  
          * Returns the current {@link org.jdom2.JDOMFactory} in use.
 380  
          * 
 381  
          * @return the factory in use
 382  
          */
 383  
         @Override
 384  
         public JDOMFactory getJDOMFactory() {
 385  6
                 return jdomfac;
 386  
         }
 387  
 
 388  
         /**
 389  
          * This sets a custom JDOMFactory for the builder. Use this to build the
 390  
          * tree with your own subclasses of the JDOM classes.
 391  
          * 
 392  
          * @param factory
 393  
          *        <code>JDOMFactory</code> to use
 394  
          * @deprecated as it is replaced by {@link #setJDOMFactory(JDOMFactory)}
 395  
          */
 396  
         @Deprecated
 397  
         public void setFactory(final JDOMFactory factory) {
 398  1
                 setJDOMFactory(factory);
 399  1
         }
 400  
 
 401  
         /**
 402  
          * This sets a custom JDOMFactory for the builder. Use this to build the
 403  
          * tree with your own subclasses of the JDOM classes.
 404  
          * 
 405  
          * @param factory
 406  
          *        <code>JDOMFactory</code> to use
 407  
          */
 408  
         public void setJDOMFactory(final JDOMFactory factory) {
 409  3
                 this.jdomfac = factory;
 410  3
                 engine = null;
 411  3
         }
 412  
 
 413  
         /**
 414  
          * Get the current XMLReader factory.
 415  
          * 
 416  
          * @return the current JDOMXMLReaderFactory
 417  
          */
 418  
         public XMLReaderJDOMFactory getXMLReaderFactory() {
 419  2
                 return readerfac;
 420  
         }
 421  
 
 422  
         /**
 423  
          * Set the current XMLReader factory.
 424  
          * 
 425  
          * @param rfac
 426  
          *        the JDOMXMLReaderFactory to set. A null rfac will indicate the
 427  
          *        default {@link XMLReaders#NONVALIDATING}
 428  
          */
 429  
         public void setXMLReaderFactory(final XMLReaderJDOMFactory rfac) {
 430  4
                 readerfac = rfac == null
 431  
                                 ? XMLReaders.NONVALIDATING
 432  
                                 : rfac;
 433  4
                 engine = null;
 434  4
         }
 435  
 
 436  
         /**
 437  
          * Get the SAXHandlerFactory used to supply SAXHandlers to this SAXBuilder.
 438  
          * 
 439  
          * @return the current SAXHandlerFactory (never null).
 440  
          */
 441  
         public SAXHandlerFactory getSAXHandlerFactory() {
 442  5
                 return handlerfac;
 443  
         }
 444  
 
 445  
         /**
 446  
          * Set the SAXHandlerFactory to be used by this SAXBuilder.
 447  
          * 
 448  
          * @param factory
 449  
          *        the required SAXHandlerFactory. A null input factory will request
 450  
          *        the {@link DefaultSAXHandlerFactory}.
 451  
          */
 452  
         public void setSAXHandlerFactory(final SAXHandlerFactory factory) {
 453  3
                 this.handlerfac = factory == null ? DEFAULTSAXHANDLERFAC : factory;
 454  3
                 engine = null;
 455  3
         }
 456  
 
 457  
         /**
 458  
          * Returns whether validation is to be performed during the build.
 459  
          * 
 460  
          * @return whether validation is to be performed during the build
 461  
          * @deprecated in lieu of {@link #isValidating()}
 462  
          */
 463  
         @Deprecated
 464  
         public boolean getValidation() {
 465  5
                 return isValidating();
 466  
         }
 467  
 
 468  
         /**
 469  
          * Returns whether validation is to be performed during the build.
 470  
          * 
 471  
          * @return whether validation is to be performed during the build
 472  
          */
 473  
         @Override
 474  
         public boolean isValidating() {
 475  29
                 return readerfac.isValidating();
 476  
         }
 477  
 
 478  
         /**
 479  
          * This sets validation for the builder.
 480  
          * <p>
 481  
          * <b>Do Not Use</b>
 482  
          * <p>
 483  
          * JDOM2 introduces the concept of XMLReader factories. The XMLReader is
 484  
          * what determines the type of validation. A simple boolean is not enough to
 485  
          * indicate what sort of validation is required. The
 486  
          * {@link #setXMLReaderFactory(XMLReaderJDOMFactory)} method provides a
 487  
          * means to be more specific about validation.
 488  
          * <p>
 489  
          * For backward compatibility this method has been retained, but its use is
 490  
          * discouraged. It does make some logical choices though. The code is
 491  
          * equivalent to:
 492  
          * <p>
 493  
          * 
 494  
          * <pre>
 495  
          * setXMLReaderFactory(XMLReaders.DTDVALIDATING)
 496  
          * </pre>
 497  
          * 
 498  
          * for true, and
 499  
          * 
 500  
          * <pre>
 501  
          * setXMLReaderFactory(XMLReaders.NONVALIDATING)
 502  
          * </pre>
 503  
          * 
 504  
          * for false.
 505  
          * 
 506  
          * @see #setXMLReaderFactory(XMLReaderJDOMFactory)
 507  
          * @see XMLReaders#NONVALIDATING
 508  
          * @see XMLReaders#DTDVALIDATING
 509  
          * @param validate
 510  
          *        <code>boolean</code> indicating whether validation should occur.
 511  
          * @deprecated use {@link #setXMLReaderFactory(XMLReaderJDOMFactory)}
 512  
          */
 513  
         @Deprecated
 514  
         public void setValidation(final boolean validate) {
 515  2
                 setXMLReaderFactory(validate
 516  
                                 ? XMLReaders.DTDVALIDATING
 517  
                                 : XMLReaders.NONVALIDATING);
 518  2
         }
 519  
 
 520  
         /**
 521  
          * Returns the {@link ErrorHandler} assigned, or null if none. When the
 522  
          * SAXBuilder parses a document it will always have an ErrorHandler but it
 523  
          * will be an instance of {@link BuilderErrorHandler} unless you specify a
 524  
          * different ErrorHandler in {@link #setErrorHandler(ErrorHandler)}. In
 525  
          * other words, a null return value from here indicates a default will be
 526  
          * used.
 527  
          * 
 528  
          * @return the ErrorHandler assigned, or null if SAXBuilder will create a
 529  
          *         default ErrorHandler when needed.
 530  
          */
 531  
         @Override
 532  
         public ErrorHandler getErrorHandler() {
 533  9
                 return saxErrorHandler;
 534  
         }
 535  
 
 536  
         /**
 537  
          * This sets custom ErrorHandler for the Builder. Setting a null value will
 538  
          * indicate SAXBuilder should create a default ErrorHandler when needed.
 539  
          * 
 540  
          * @param errorHandler
 541  
          *        <code>ErrorHandler</code>
 542  
          */
 543  
         public void setErrorHandler(final ErrorHandler errorHandler) {
 544  1
                 saxErrorHandler = errorHandler;
 545  1
                 engine = null;
 546  1
         }
 547  
 
 548  
         /**
 549  
          * Returns the {@link EntityResolver} assigned, or null if none.
 550  
          * 
 551  
          * @return the EntityResolver assigned
 552  
          */
 553  
         @Override
 554  
         public EntityResolver getEntityResolver() {
 555  21
                 return saxEntityResolver;
 556  
         }
 557  
 
 558  
         /**
 559  
          * This sets custom EntityResolver for the <code>Builder</code>.
 560  
          * 
 561  
          * @param entityResolver
 562  
          *        <code>EntityResolver</code>
 563  
          */
 564  
         public void setEntityResolver(final EntityResolver entityResolver) {
 565  1
                 saxEntityResolver = entityResolver;
 566  1
                 engine = null;
 567  1
         }
 568  
 
 569  
         /**
 570  
          * Returns the {@link DTDHandler} assigned, or null if the assigned
 571  
          * {@link SAXHandler} will be used for DTD SAX events.
 572  
          * 
 573  
          * @return the DTDHandler assigned
 574  
          */
 575  
         @Override
 576  
         public DTDHandler getDTDHandler() {
 577  21
                 return saxDTDHandler;
 578  
         }
 579  
 
 580  
         /**
 581  
          * This sets custom DTDHandler for the <code>Builder</code>. Setting a null
 582  
          * value indicates that SAXBuilder should use the assigned SAXHandler for
 583  
          * DTD processing.
 584  
          * 
 585  
          * @param dtdHandler
 586  
          *        <code>DTDHandler</code>
 587  
          */
 588  
         public void setDTDHandler(final DTDHandler dtdHandler) {
 589  1
                 saxDTDHandler = dtdHandler;
 590  1
                 engine = null;
 591  1
         }
 592  
 
 593  
         /**
 594  
          * Returns the {@link XMLFilter} used during parsing, or null if none.
 595  
          * 
 596  
          * @return the XMLFilter used during parsing
 597  
          */
 598  
         public XMLFilter getXMLFilter() {
 599  21
                 return saxXMLFilter;
 600  
         }
 601  
 
 602  
         /**
 603  
          * This sets a custom {@link org.xml.sax.XMLFilter} for the builder.
 604  
          * <p>
 605  
          * Care should be taken to ensure that the specified xmlFilter is reentrant
 606  
          * and thread-safe.
 607  
          * <p>
 608  
          * SAXBuilder will set this instance as the parent instance for all
 609  
          * XMLReaders that may be created, and these may (depending on SAXBuilder
 610  
          * usage) be accessed concurrently. It is the responsibility of the JDOM
 611  
          * user to ensure that if the XMLFilter is not thread-safe then neither the
 612  
          * SAXBuilder nor any of it's SAXEngines are accessed concurrently.
 613  
          * 
 614  
          * @param xmlFilter
 615  
          *        the XMLFilter to use
 616  
          */
 617  
         public void setXMLFilter(final XMLFilter xmlFilter) {
 618  1
                 saxXMLFilter = xmlFilter;
 619  1
                 engine = null;
 620  1
         }
 621  
 
 622  
         /**
 623  
          * Returns whether element content whitespace is to be ignored during the
 624  
          * build.
 625  
          * 
 626  
          * @return whether element content whitespace is to be ignored during the
 627  
          *         build
 628  
          */
 629  
         @Override
 630  
         public boolean getIgnoringElementContentWhitespace() {
 631  2
                 return ignoringWhite;
 632  
         }
 633  
 
 634  
         /**
 635  
          * Specifies whether or not the parser should eliminate whitespace in
 636  
          * element content (sometimes known as "ignorable whitespace") when building
 637  
          * the document. Only whitespace which is contained within element content
 638  
          * that has an element only content model will be eliminated (see XML Rec
 639  
          * 3.2.1). For this setting to take effect requires that validation be
 640  
          * turned on. The default value of this setting is <code>false</code>.
 641  
          * 
 642  
          * @param ignoringWhite
 643  
          *        Whether to ignore ignorable whitespace
 644  
          */
 645  
         public void setIgnoringElementContentWhitespace(final boolean ignoringWhite) {
 646  2
                 this.ignoringWhite = ignoringWhite;
 647  2
                 engine = null;
 648  2
         }
 649  
 
 650  
         /**
 651  
          * Returns whether or not the parser will eliminate element content
 652  
          * containing only whitespace.
 653  
          * 
 654  
          * @return <code>boolean</code> - whether only whitespace content will be
 655  
          *         ignored during build.
 656  
          * @see #setIgnoringBoundaryWhitespace
 657  
          */
 658  
         @Override
 659  
         public boolean getIgnoringBoundaryWhitespace() {
 660  2
                 return ignoringBoundaryWhite;
 661  
         }
 662  
 
 663  
         /**
 664  
          * Specifies whether or not the parser should elminate boundary whitespace,
 665  
          * a term that indicates whitespace-only text between element tags. This
 666  
          * feature is a lot like
 667  
          * {@link #setIgnoringElementContentWhitespace(boolean)} but this feature is
 668  
          * more aggressive and doesn't require validation be turned on. The
 669  
          * {@link #setIgnoringElementContentWhitespace(boolean)} call impacts the
 670  
          * SAX parse process while this method impacts the JDOM build process, so it
 671  
          * can be beneficial to turn both on for efficiency. For implementation
 672  
          * efficiency, this method actually removes all whitespace-only text()
 673  
          * nodes. That can, in some cases (like between an element tag and a
 674  
          * comment) include whitespace that isn't just boundary whitespace. The
 675  
          * default is <code>false</code>.
 676  
          * 
 677  
          * @param ignoringBoundaryWhite
 678  
          *        Whether to ignore whitespace-only text nodes
 679  
          */
 680  
         public void setIgnoringBoundaryWhitespace(final boolean ignoringBoundaryWhite) {
 681  2
                 this.ignoringBoundaryWhite = ignoringBoundaryWhite;
 682  2
                 engine = null;
 683  2
         }
 684  
 
 685  
         /**
 686  
          * Returns whether or not entities are being expanded into normal text
 687  
          * content.
 688  
          * 
 689  
          * @return whether entities are being expanded
 690  
          */
 691  
         @Override
 692  
         public boolean getExpandEntities() {
 693  24
                 return expand;
 694  
         }
 695  
 
 696  
         /**
 697  
          * <p>
 698  
          * This sets whether or not to expand entities for the builder. A true means
 699  
          * to expand entities as normal content. A false means to leave entities
 700  
          * unexpanded as <code>EntityRef</code> objects. The default is true.
 701  
          * </p>
 702  
          * <p>
 703  
          * When this setting is false, the internal DTD subset is retained; when
 704  
          * this setting is true, the internal DTD subset is not retained.
 705  
          * </p>
 706  
          * <p>
 707  
          * Note that Xerces (at least up to 1.4.4) has a bug where entities in
 708  
          * attribute values will be incorrectly reported if this flag is turned off,
 709  
          * resulting in entities appearing within element content. When turning
 710  
          * entity expansion off either avoid entities in attribute values, or use
 711  
          * another parser like Crimson.
 712  
          * http://nagoya.apache.org/bugzilla/show_bug.cgi?id=6111
 713  
          * </p>
 714  
          * 
 715  
          * @param expand
 716  
          *        <code>boolean</code> indicating whether entity expansion should
 717  
          *        occur.
 718  
          */
 719  
         public void setExpandEntities(final boolean expand) {
 720  75
                 this.expand = expand;
 721  75
                 engine = null;
 722  75
         }
 723  
 
 724  
         /**
 725  
          * Returns whether the contained SAX parser instance is reused across
 726  
          * multiple parses. The default is true.
 727  
          * 
 728  
          * @return whether the contained SAX parser instance is reused across
 729  
          *         multiple parses
 730  
          */
 731  
         public boolean getReuseParser() {
 732  2
                 return reuseParser;
 733  
         }
 734  
 
 735  
         /**
 736  
          * Specifies whether this builder will reuse the same SAX parser when
 737  
          * performing subsequent parses or allocate a new parser for each parse. The
 738  
          * default value of this setting is <code>true</code> (parser reuse).
 739  
          * <p>
 740  
          * <strong>Note</strong>: SAX parser instances are not thread safe (they are
 741  
          * not even reentrant), and nor are SAXBuilder instances. Setting parser
 742  
          * reuse does not imply the parser is thread-safe.
 743  
          * </p>
 744  
          * 
 745  
          * @param reuseParser
 746  
          *        Whether to reuse the SAX parser.
 747  
          */
 748  
         public void setReuseParser(final boolean reuseParser) {
 749  10
                 this.reuseParser = reuseParser;
 750  10
                 if (!reuseParser) {
 751  9
                         engine = null;
 752  
                 }
 753  10
         }
 754  
 
 755  
         /**
 756  
          * Specifies whether this builder will do fast reconfiguration of the
 757  
          * underlying SAX parser when reuseParser is true. This improves performance
 758  
          * in cases where SAXBuilders are reused and lots of small documents are
 759  
          * frequently parsed. This avoids attempting to set features on the SAX
 760  
          * parser each time build() is called which result in
 761  
          * SaxNotRecognizedExceptions. This should ONLY be set for builders where
 762  
          * this specific case is an issue. The default value of this setting is
 763  
          * <code>false</code> (no fast reconfiguration). If reuseParser is false,
 764  
          * calling this has no effect.
 765  
          * 
 766  
          * @param fastReconfigure
 767  
          *        Whether to do a fast reconfiguration of the parser
 768  
          * @deprecated All reused Parsers are now fast-reconfigured. No need to set
 769  
          *             it.
 770  
          */
 771  
         @Deprecated
 772  
         public void setFastReconfigure(final boolean fastReconfigure) {
 773  
                 // do nothing
 774  1
         }
 775  
 
 776  
         /**
 777  
          * This sets a feature on the SAX parser. See the SAX documentation for
 778  
          * more information. </p>
 779  
          * <p>
 780  
          * NOTE: SAXBuilder requires that some particular features of the SAX parser
 781  
          * be set up in certain ways for it to work properly. The list of such
 782  
          * features may change in the future. Therefore, the use of this method may
 783  
          * cause parsing to break, and even if it doesn't break anything today it
 784  
          * might break parsing in a future JDOM version, because what JDOM parsers
 785  
          * require may change over time. Use with caution.
 786  
          * </p>
 787  
          * JDOM uses {@link XMLReaderJDOMFactory} instances to provide XMLReader
 788  
          * instances. If you require special configuration on your XMLReader you
 789  
          * should consider extending or implementing an XMLReaderJDOMFactory in the
 790  
          * {@link org.jdom2.input.sax} package.
 791  
          * 
 792  
          * @param name
 793  
          *        The feature name, which is a fully-qualified URI.
 794  
          * @param value
 795  
          *        The requested state of the feature (true or false).
 796  
          */
 797  
         public void setFeature(final String name, final boolean value) {
 798  
                 // Save the specified feature for later.
 799  5
                 features.put(name, value ? Boolean.TRUE : Boolean.FALSE);
 800  5
                 engine = null;
 801  5
         }
 802  
 
 803  
         /**
 804  
          * This sets a property on the SAX parser. See the SAX documentation for
 805  
          * more information.
 806  
          * <p>
 807  
          * NOTE: SAXBuilder requires that some particular properties of the SAX
 808  
          * parser be set up in certain ways for it to work properly. The list of
 809  
          * such properties may change in the future. Therefore, the use of this
 810  
          * method may cause parsing to break, and even if it doesn't break anything
 811  
          * today it might break parsing in a future JDOM version, because what JDOM
 812  
          * parsers require may change over time. Use with caution.
 813  
          * </p>
 814  
          * JDOM uses {@link XMLReaderJDOMFactory} instances to provide XMLReader
 815  
          * instances. If you require special configuration on your XMLReader you
 816  
          * should consider extending or implementing an XMLReaderJDOMFactory in the
 817  
          * {@link org.jdom2.input.sax} package.
 818  
          * 
 819  
          * @param name
 820  
          *        The property name, which is a fully-qualified URI.
 821  
          * @param value
 822  
          *        The requested value for the property.
 823  
          */
 824  
         public void setProperty(final String name, final Object value) {
 825  
                 // Save the specified property for later.
 826  3
                 properties.put(name, value);
 827  3
                 engine = null;
 828  3
         }
 829  
 
 830  
         /**
 831  
          * This method builds a new and reusable {@link SAXEngine}.
 832  
          * Each time this method is called a new instance of a SAXEngine will be
 833  
          * returned.
 834  
          * <p>
 835  
          * This method is used internally by the various SAXBuilder.build(*) methods
 836  
          * (if any configuration has changed) but can also be used as a mechanism
 837  
          * for creating SAXEngines to be used in parsing pools or other optimised
 838  
          * structures.
 839  
          * 
 840  
          * @return a {@link SAXEngine} representing the current state of the
 841  
          *         current SAXBuilder settings.
 842  
          * @throws JDOMException
 843  
          *         if there is any problem initialising the engine.
 844  
          */
 845  
         public SAXEngine buildEngine() throws JDOMException {
 846  
 
 847  
                 // Create and configure the content handler.
 848  156
                 final SAXHandler contentHandler = handlerfac.createSAXHandler(jdomfac);
 849  
 
 850  156
                 contentHandler.setExpandEntities(expand);
 851  156
                 contentHandler.setIgnoringElementContentWhitespace(ignoringWhite);
 852  156
                 contentHandler.setIgnoringBoundaryWhitespace(ignoringBoundaryWhite);
 853  
 
 854  156
                 final XMLReader parser = createParser();
 855  
                 // Configure parser
 856  156
                 configureParser(parser, contentHandler);
 857  156
                 final boolean valid = readerfac.isValidating();
 858  
 
 859  156
                 return new SAXBuilderEngine(parser, contentHandler, valid);
 860  
         }
 861  
 
 862  
         /**
 863  
          * Allow overriding classes access to the Parser before it is used in a
 864  
          * SAXBuilderEngine.
 865  
          * 
 866  
          * @return a XMLReader parser.
 867  
          * @throws JDOMException
 868  
          *         if there is a problem
 869  
          */
 870  
         protected XMLReader createParser() throws JDOMException {
 871  165
                 XMLReader parser = readerfac.createXMLReader();
 872  
 
 873  
                 // Install optional filter
 874  165
                 if (saxXMLFilter != null) {
 875  
                         // Connect filter chain to parser
 876  1
                         XMLFilter root = saxXMLFilter;
 877  2
                         while (root.getParent() instanceof XMLFilter) {
 878  1
                                 root = (XMLFilter) root.getParent();
 879  
                         }
 880  1
                         root.setParent(parser);
 881  
 
 882  
                         // Read from filter
 883  1
                         parser = saxXMLFilter;
 884  
                 }
 885  
 
 886  165
                 return parser;
 887  
         }
 888  
 
 889  
         /**
 890  
          * This method retrieves (or builds) a SAXBuilderEngine that represents the
 891  
          * current SAXBuilder state.
 892  
          * 
 893  
          * @return a {@link SAXBuilderEngine} representing the current state of the
 894  
          *         current SAXBuilder settings.
 895  
          * @throws JDOMException
 896  
          *         if there is any problem initializing the engine.
 897  
          */
 898  
         private SAXEngine getEngine() throws JDOMException {
 899  
 
 900  146
                 if (engine != null) {
 901  8
                         return engine;
 902  
                 }
 903  
 
 904  138
                 engine = buildEngine();
 905  138
                 return engine;
 906  
         }
 907  
 
 908  
         /**
 909  
          * This configures the XMLReader to be used for reading the XML document.
 910  
          * <p>
 911  
          * The default implementation sets various options on the given XMLReader,
 912  
          * such as validation, DTD resolution, entity handlers, etc., according to
 913  
          * the options that were set (e.g. via <code>setEntityResolver</code>) and
 914  
          * set various SAX properties and features that are required for JDOM
 915  
          * internals. These features may change in future releases, so change this
 916  
          * behavior at your own risk.
 917  
          * </p>
 918  
          * 
 919  
          * @param parser
 920  
          *        the XMLReader to configure.
 921  
          * @param contentHandler
 922  
          *        The SAXHandler to use for the XMLReader
 923  
          * @throws JDOMException
 924  
          *         if configuration fails.
 925  
          */
 926  
         protected void configureParser(final XMLReader parser, final SAXHandler contentHandler)
 927  
                         throws JDOMException {
 928  
 
 929  
                 // Setup SAX handlers.
 930  
 
 931  166
                 parser.setContentHandler(contentHandler);
 932  
 
 933  166
                 if (saxEntityResolver != null) {
 934  0
                         parser.setEntityResolver(saxEntityResolver);
 935  
                 }
 936  
 
 937  166
                 if (saxDTDHandler != null) {
 938  0
                         parser.setDTDHandler(saxDTDHandler);
 939  
                 } else {
 940  166
                         parser.setDTDHandler(contentHandler);
 941  
                 }
 942  
 
 943  166
                 if (saxErrorHandler != null) {
 944  1
                         parser.setErrorHandler(saxErrorHandler);
 945  
                 } else {
 946  165
                         parser.setErrorHandler(new BuilderErrorHandler());
 947  
                 }
 948  
 
 949  166
                 boolean success = false;
 950  
 
 951  
                 try {
 952  166
                         parser.setProperty(SAX_PROPERTY_LEXICAL_HANDLER,
 953  
                                         contentHandler);
 954  166
                         success = true;
 955  0
                 } catch (final SAXNotSupportedException e) {
 956  
                         // No lexical reporting available
 957  0
                 } catch (final SAXNotRecognizedException e) {
 958  
                         // No lexical reporting available
 959  166
                 }
 960  
 
 961  
                 // Some parsers use alternate property for lexical handling (grr...)
 962  166
                 if (!success) {
 963  
                         try {
 964  0
                                 parser.setProperty(SAX_PROPERTY_LEXICAL_HANDLER_ALT,
 965  
                                                 contentHandler);
 966  0
                                 success = true;
 967  0
                         } catch (final SAXNotSupportedException e) {
 968  
                                 // No lexical reporting available
 969  0
                         } catch (final SAXNotRecognizedException e) {
 970  
                                 // No lexical reporting available
 971  0
                         }
 972  
                 }
 973  
 
 974  
                 // Set any user-specified features on the parser.
 975  166
                 for (final Map.Entry<String, Boolean> me : features.entrySet()) {
 976  5
                         internalSetFeature(parser, me.getKey(), me.getValue().booleanValue(), me.getKey());
 977  5
                 }
 978  
 
 979  
                 // Set any user-specified properties on the parser.
 980  166
                 for (final Map.Entry<String, Object> me : properties.entrySet()) {
 981  2
                         internalSetProperty(parser, me.getKey(), me.getValue(), me.getKey());
 982  1
                 }
 983  
 
 984  
                 // Set entity expansion
 985  
                 // Note SAXHandler can work regardless of how this is set, but when
 986  
                 // entity expansion it's worth it to try to tell the parser not to
 987  
                 // even bother with external general entities.
 988  
                 // Apparently no parsers yet support this feature.
 989  
                 // XXX It might make sense to setEntityResolver() with a resolver
 990  
                 // that simply ignores external general entities
 991  
                 try {
 992  165
                         if (parser.getFeature(SAX_FEATURE_EXTERNAL_ENT) != expand) {
 993  33
                                 parser.setFeature(SAX_FEATURE_EXTERNAL_ENT, expand);
 994  
                         }
 995  0
                 } catch (final SAXException e) { /* Ignore... */
 996  165
                 }
 997  
 
 998  
                 // Try setting the DeclHandler if entity expansion is off
 999  165
                 if (!expand) {
 1000  
                         try {
 1001  33
                                 parser.setProperty(SAX_PROPERTY_DECLARATION_HANDLER,
 1002  
                                                 contentHandler);
 1003  33
                                 success = true;
 1004  0
                         } catch (final SAXNotSupportedException e) {
 1005  
                                 // No lexical reporting available
 1006  0
                         } catch (final SAXNotRecognizedException e) {
 1007  
                                 // No lexical reporting available
 1008  33
                         }
 1009  
                 }
 1010  
 
 1011  165
         }
 1012  
 
 1013  
         /**
 1014  
          * Tries to set a feature on the parser. If the feature cannot be set,
 1015  
          * throws a JDOMException describing the problem.
 1016  
          */
 1017  
         private void internalSetFeature(final XMLReader parser, final String feature,
 1018  
                         final boolean value, final String displayName) throws JDOMException {
 1019  
                 try {
 1020  5
                         parser.setFeature(feature, value);
 1021  0
                 } catch (final SAXNotSupportedException e) {
 1022  0
                         throw new JDOMException(
 1023  
                                         displayName + " feature not supported for SAX driver " + parser.getClass().getName());
 1024  0
                 } catch (final SAXNotRecognizedException e) {
 1025  0
                         throw new JDOMException(
 1026  
                                         displayName + " feature not recognized for SAX driver " + parser.getClass().getName());
 1027  5
                 }
 1028  5
         }
 1029  
 
 1030  
         /**
 1031  
          * <p>
 1032  
          * Tries to set a property on the parser. If the property cannot be set,
 1033  
          * throws a JDOMException describing the problem.
 1034  
          * </p>
 1035  
          */
 1036  
         private void internalSetProperty(final XMLReader parser, final String property,
 1037  
                         final Object value, final String displayName) throws JDOMException {
 1038  
                 try {
 1039  2
                         parser.setProperty(property, value);
 1040  1
                 } catch (final SAXNotSupportedException e) {
 1041  1
                         throw new JDOMException(
 1042  
                                         displayName + " property not supported for SAX driver " + parser.getClass().getName());
 1043  0
                 } catch (final SAXNotRecognizedException e) {
 1044  0
                         throw new JDOMException(
 1045  
                                         displayName + " property not recognized for SAX driver " + parser.getClass().getName());
 1046  1
                 }
 1047  1
         }
 1048  
 
 1049  
         /**
 1050  
          * This builds a document from the supplied input source.
 1051  
          * 
 1052  
          * @param in
 1053  
          *        <code>InputSource</code> to read from
 1054  
          * @return <code>Document</code> resultant Document object
 1055  
          * @throws JDOMException
 1056  
          *         when errors occur in parsing
 1057  
          * @throws IOException
 1058  
          *         when an I/O error prevents a document from being fully parsed
 1059  
          */
 1060  
         @Override
 1061  
         public Document build(final InputSource in)
 1062  
                         throws JDOMException, IOException {
 1063  
 
 1064  
                 try {
 1065  4
                         return getEngine().build(in);
 1066  
                 } finally {
 1067  4
                         if (!reuseParser) {
 1068  2
                                 engine = null;
 1069  
                         }
 1070  
                 }
 1071  
 
 1072  
         }
 1073  
 
 1074  
         /**
 1075  
          * <p>
 1076  
          * This builds a document from the supplied input stream.
 1077  
          * </p>
 1078  
          * 
 1079  
          * @param in
 1080  
          *        <code>InputStream</code> to read from
 1081  
          * @return <code>Document</code> resultant Document object
 1082  
          * @throws JDOMException
 1083  
          *         when errors occur in parsing
 1084  
          * @throws IOException
 1085  
          *         when an I/O error prevents a document from being fully parsed.
 1086  
          */
 1087  
         @Override
 1088  
         public Document build(final InputStream in)
 1089  
                         throws JDOMException, IOException {
 1090  
                 try {
 1091  17
                         return getEngine().build(in);
 1092  
                 } finally {
 1093  17
                         if (!reuseParser) {
 1094  2
                                 engine = null;
 1095  
                         }
 1096  
                 }
 1097  
         }
 1098  
 
 1099  
         /**
 1100  
          * <p>
 1101  
          * This builds a document from the supplied filename.
 1102  
          * </p>
 1103  
          * 
 1104  
          * @param file
 1105  
          *        <code>File</code> to read from
 1106  
          * @return <code>Document</code> resultant Document object
 1107  
          * @throws JDOMException
 1108  
          *         when errors occur in parsing
 1109  
          * @throws IOException
 1110  
          *         when an I/O error prevents a document from being fully parsed
 1111  
          */
 1112  
         @Override
 1113  
         public Document build(final File file)
 1114  
                         throws JDOMException, IOException {
 1115  
                 try {
 1116  4
                         return getEngine().build(file);
 1117  
                 } finally {
 1118  4
                         if (!reuseParser) {
 1119  2
                                 engine = null;
 1120  
                         }
 1121  
                 }
 1122  
         }
 1123  
 
 1124  
         /**
 1125  
          * <p>
 1126  
          * This builds a document from the supplied URL.
 1127  
          * </p>
 1128  
          * 
 1129  
          * @param url
 1130  
          *        <code>URL</code> to read from.
 1131  
          * @return <code>Document</code> - resultant Document object.
 1132  
          * @throws JDOMException
 1133  
          *         when errors occur in parsing
 1134  
          * @throws IOException
 1135  
          *         when an I/O error prevents a document from being fully parsed.
 1136  
          */
 1137  
         @Override
 1138  
         public Document build(final URL url)
 1139  
                         throws JDOMException, IOException {
 1140  
                 try {
 1141  63
                         return getEngine().build(url);
 1142  
                 } finally {
 1143  63
                         if (!reuseParser) {
 1144  2
                                 engine = null;
 1145  
                         }
 1146  
                 }
 1147  
         }
 1148  
 
 1149  
         /**
 1150  
          * <p>
 1151  
          * This builds a document from the supplied input stream.
 1152  
          * </p>
 1153  
          * 
 1154  
          * @param in
 1155  
          *        <code>InputStream</code> to read from.
 1156  
          * @param systemId
 1157  
          *        base for resolving relative URIs
 1158  
          * @return <code>Document</code> resultant Document object
 1159  
          * @throws JDOMException
 1160  
          *         when errors occur in parsing
 1161  
          * @throws IOException
 1162  
          *         when an I/O error prevents a document from being fully parsed
 1163  
          */
 1164  
         @Override
 1165  
         public Document build(final InputStream in, final String systemId)
 1166  
                         throws JDOMException, IOException {
 1167  
                 try {
 1168  4
                         return getEngine().build(in, systemId);
 1169  
                 } finally {
 1170  4
                         if (!reuseParser) {
 1171  2
                                 engine = null;
 1172  
                         }
 1173  
                 }
 1174  
         }
 1175  
 
 1176  
         /**
 1177  
          * <p>
 1178  
          * This builds a document from the supplied Reader. It's the programmer's
 1179  
          * responsibility to make sure the reader matches the encoding of the file.
 1180  
          * It's often easier and safer to use an InputStream rather than a Reader,
 1181  
          * and to let the parser auto-detect the encoding from the XML declaration.
 1182  
          * </p>
 1183  
          * 
 1184  
          * @param characterStream
 1185  
          *        <code>Reader</code> to read from
 1186  
          * @return <code>Document</code> resultant Document object
 1187  
          * @throws JDOMException
 1188  
          *         when errors occur in parsing
 1189  
          * @throws IOException
 1190  
          *         when an I/O error prevents a document from being fully parsed
 1191  
          */
 1192  
         @Override
 1193  
         public Document build(final Reader characterStream)
 1194  
                         throws JDOMException, IOException {
 1195  
                 try {
 1196  43
                         return getEngine().build(characterStream);
 1197  
                 } finally {
 1198  43
                         if (!reuseParser) {
 1199  2
                                 engine = null;
 1200  
                         }
 1201  
                 }
 1202  
         }
 1203  
 
 1204  
         /**
 1205  
          * <p>
 1206  
          * This builds a document from the supplied Reader. It's the programmer's
 1207  
          * responsibility to make sure the reader matches the encoding of the file.
 1208  
          * It's often easier and safer to use an InputStream rather than a Reader,
 1209  
          * and to let the parser auto-detect the encoding from the XML declaration.
 1210  
          * </p>
 1211  
          * 
 1212  
          * @param characterStream
 1213  
          *        <code>Reader</code> to read from.
 1214  
          * @param systemId
 1215  
          *        base for resolving relative URIs
 1216  
          * @return <code>Document</code> resultant Document object
 1217  
          * @throws JDOMException
 1218  
          *         when errors occur in parsing
 1219  
          * @throws IOException
 1220  
          *         when an I/O error prevents a document from being fully parsed
 1221  
          */
 1222  
         @Override
 1223  
         public Document build(final Reader characterStream, final String systemId)
 1224  
                         throws JDOMException, IOException {
 1225  
 
 1226  
                 try {
 1227  4
                         return getEngine().build(characterStream, systemId);
 1228  
                 } finally {
 1229  4
                         if (!reuseParser) {
 1230  2
                                 engine = null;
 1231  
                         }
 1232  
                 }
 1233  
         }
 1234  
 
 1235  
         /**
 1236  
          * <p>
 1237  
          * This builds a document from the supplied URI. The URI is typically a file name, or a URL.
 1238  
          * Do not use this method for parsing XML content that is in a Java String variable.
 1239  
          * <p>
 1240  
          * <ul>
 1241  
          * <li><Strong>Right:</Strong> <code>....build("path/to/file.xml");</code>
 1242  
          * <li><Strong>Right:</Strong> <code>....build("http://my.example.com/xmlfile");</code>
 1243  
          * <li><Strong>Wrong:</Strong> <code>....build("&lt;root>data&lt/root>");</code>
 1244  
          * </ul>
 1245  
          * </p>
 1246  
          * If your XML content is in a Java String variable and you want to parse it, then use:<br/>
 1247  
          * <code>    ....build(new StringReader("&lt;root>data&lt/root>"));</code>
 1248  
          * <p>
 1249  
          * 
 1250  
          * @param systemId
 1251  
          *        URI for the input
 1252  
          * @return <code>Document</code> resultant Document object
 1253  
          * @throws JDOMException
 1254  
          *         when errors occur in parsing
 1255  
          * @throws IOException
 1256  
          *         when an I/O error prevents a document from being fully parsed
 1257  
          */
 1258  
         @Override
 1259  
         public Document build(final String systemId)
 1260  
                         throws JDOMException, IOException {
 1261  8
                 if (systemId == null) {
 1262  1
                         throw new NullPointerException(
 1263  
                                         "Unable to build a URI from a null systemID.");
 1264  
                 }
 1265  
                 try {
 1266  7
                         return getEngine().build(systemId);
 1267  3
                 } catch (IOException ioe) {
 1268  
                         // OK, Issue #63
 1269  
                         // it is common for people to pass in raw XML content instead of
 1270  
                         // a SystemID. To make troubleshooting easier, we do a simple check
 1271  
                         // all valid XML documents start with a '<' character.
 1272  
                         // no URI ever has an '<' character.
 1273  
                         // if we think an XML document was passed in, we wrap the exception
 1274  
                         // Typically this problem causes a MalformedURLException to be
 1275  
                         // thrown, but that is not particular specified that way. Of
 1276  
                         // interest, depending on the broken systemID, you could get a
 1277  
                         // FileNotFoundException which is also an IOException, which will
 1278  
                         // also be processed by this handler....
 1279  
                         
 1280  3
                         final int len = systemId.length();
 1281  3
                         int i = 0;
 1282  7
                         while (i < len && Verifier.isXMLWhitespace(systemId.charAt(i))) {
 1283  4
                                 i++;
 1284  
                         }
 1285  3
                         if (i < len && '<' == systemId.charAt(i)) {
 1286  
                                 // our systemID URI has a '<' - this is likely the problem. 
 1287  2
                                 MalformedURLException mx = new MalformedURLException(
 1288  
                                                 "SAXBuilder.build(String) expects the String to be " +
 1289  
                                                 "a systemID, but in this instance it appears to be " +
 1290  
                                                 "actual XML data.");
 1291  
                                 // include the original problem for accountability, and perhaps
 1292  
                                 // a false positive.... though very unlikely
 1293  2
                                 mx.initCause(ioe);
 1294  2
                                 throw mx;
 1295  
                         }
 1296  
                         // it is likely not an XML document - re-throw the exception  
 1297  1
                         throw ioe;
 1298  
                 } finally {
 1299  7
                         if (!reuseParser) {
 1300  2
                                 engine = null;
 1301  
                         }
 1302  
                 }
 1303  
         }
 1304  
 
 1305  
 }