Projects
Eulaceura:Mainline
dom4j
_service:obs_scm:backport-CVE-2020-10683-SAXRea...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:obs_scm:backport-CVE-2020-10683-SAXReader-uses-system-default-XMLReader-with-its-defaults.patch of Package dom4j
From a8228522a99a02146106672a34c104adbda5c658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Jirs=C3=A1k?= <filip@jirsak.org> Date: Sat, 11 Apr 2020 19:06:44 +0200 Subject: [PATCH] SAXReader uses system default XMLReader with its defaults. New factory method SAXReader.createDefault() sets more secure defaults. --- src/main/java/org/dom4j/DocumentHelper.java | 65 +- src/main/java/org/dom4j/io/SAXHelper.java | 37 +- src/main/java/org/dom4j/io/SAXReader.java | 1824 ++++++++++--------- 3 files changed, 973 insertions(+), 953 deletions(-) diff --git a/src/main/java/org/dom4j/DocumentHelper.java b/src/main/java/org/dom4j/DocumentHelper.java index 6ceed9a3..865a51a1 100644 --- a/src/main/java/org/dom4j/DocumentHelper.java +++ b/src/main/java/org/dom4j/DocumentHelper.java @@ -107,12 +107,12 @@ public static QName createQName(String localName) { * XPath <code>XPath</code> instance using the singleton {@link * DocumentFactory}. * </p> - * + * * @param xpathExpression * is the XPath expression to create - * + * * @return a new <code>XPath</code> instance - * + * * @throws InvalidXPathException * if the XPath expression is invalid */ @@ -127,14 +127,14 @@ public static XPath createXPath(String xpathExpression) * XPath <code>XPath</code> instance using the singleton {@link * DocumentFactory}. * </p> - * + * * @param xpathExpression * is the XPath expression to create * @param context * is the variable context to use when evaluating the XPath - * + * * @return a new <code>XPath</code> instance - * + * * @throws InvalidXPathException * if the XPath expression is invalid */ @@ -150,10 +150,10 @@ public static XPath createXPath(String xpathExpression, * filter expressions occur within XPath expressions such as * <code>self::node()[ filterExpression ]</code> * </p> - * + * * @param xpathFilterExpression * is the XPath filter expression to create - * + * * @return a new <code>NodeFilter</code> instance */ public static NodeFilter createXPathFilter(String xpathFilterExpression) { @@ -166,10 +166,10 @@ public static NodeFilter createXPathFilter(String xpathFilterExpression) { * an XSLT style {@link Pattern}instance which can then be used in an XSLT * processing model. * </p> - * + * * @param xpathPattern * is the XPath pattern expression to create - * + * * @return a new <code>Pattern</code> instance */ public static Pattern createPattern(String xpathPattern) { @@ -182,12 +182,12 @@ public static Pattern createPattern(String xpathPattern) { * {@link List}of {@link Node}instances appending all the results together * into a single list. * </p> - * + * * @param xpathFilterExpression * is the XPath filter expression to evaluate * @param nodes * is the list of nodes on which to evalute the XPath - * + * * @return the results of all the XPath evaluations as a single list */ public static List<Node> selectNodes(String xpathFilterExpression, List<Node> nodes) { @@ -202,12 +202,12 @@ public static Pattern createPattern(String xpathPattern) { * {@link List}of {@link Node}instances appending all the results together * into a single list. * </p> - * + * * @param xpathFilterExpression * is the XPath filter expression to evaluate * @param node * is the Node on which to evalute the XPath - * + * * @return the results of all the XPath evaluations as a single list */ public static List<Node> selectNodes(String xpathFilterExpression, Node node) { @@ -221,7 +221,7 @@ public static Pattern createPattern(String xpathPattern) { * <code>sort</code> sorts the given List of Nodes using an XPath * expression as a {@link java.util.Comparator}. * </p> - * + * * @param list * is the list of Nodes to sort * @param xpathExpression @@ -238,7 +238,7 @@ public static void sort(List<Node> list, String xpathExpression) { * expression as a {@link java.util.Comparator}and optionally removing * duplicates. * </p> - * + * * @param list * is the list of Nodes to sort * @param expression @@ -259,24 +259,17 @@ public static void sort(List<Node> list, String expression, boolean distinct) { * </p> * * Loading external DTD and entities is disabled (if it is possible) for security reasons. - * + * * @param text * the XML text to be parsed - * + * * @return a newly parsed Document - * + * * @throws DocumentException * if the document could not be parsed */ public static Document parseText(String text) throws DocumentException { - SAXReader reader = new SAXReader(); - try { - reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); - reader.setFeature("http://xml.org/sax/features/external-general-entities", false); - reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - } catch (SAXException e) { - //Parse with external resources downloading allowed. - } + SAXReader reader = SAXReader.createDefault(); String encoding = getEncoding(text); @@ -330,14 +323,14 @@ private static String getEncoding(String text) { * get the first child <a> element, which would be created if it did * not exist, then the next child <b> and so on until finally a * <c> element is returned. - * + * * @param source * is the Element or Document to start navigating from * @param path * is a simple path expression, seperated by '/' which denotes * the path from the source to the resulting element such as * a/b/c - * + * * @return the first Element on the given path which either already existed * on the path or were created by this method. */ @@ -386,24 +379,24 @@ public static Element makeElement(Branch source, String path) { * Redistribution and use of this software and associated documentation * ("Software"), with or without modification, are permitted provided that the * following conditions are met: - * + * * 1. Redistributions of source code must retain copyright statements and * notices. Redistributions must also contain a copy of this document. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * 3. The name "DOM4J" must not be used to endorse or promote products derived * from this Software without prior written permission of MetaStuff, Ltd. For * written permission, please contact dom4j-info@metastuff.com. - * + * * 4. Products derived from this Software may not be called "DOM4J" nor may * "DOM4J" appear in their names without prior written permission of MetaStuff, * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd. - * + * * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org - * + * * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -415,6 +408,6 @@ public static Element makeElement(Branch source, String path) { * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. - * + * * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved. */ diff --git a/src/main/java/org/dom4j/io/SAXHelper.java b/src/main/java/org/dom4j/io/SAXHelper.java index d204d084..e66905e9 100644 --- a/src/main/java/org/dom4j/io/SAXHelper.java +++ b/src/main/java/org/dom4j/io/SAXHelper.java @@ -13,12 +13,14 @@ import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; +import javax.xml.parsers.SAXParserFactory; + /** * <p> * <code>SAXHelper</code> contains some helper methods for working with SAX * and XMLReader objects. * </p> - * + * * @author <a href="mailto:james.strachan@metastuff.com">James Strachan </a> * @version $Revision: 1.18 $ */ @@ -61,12 +63,21 @@ public static boolean setParserFeature(XMLReader reader, /** * Creats a default XMLReader via the org.xml.sax.driver system property or * JAXP if the system property is not set. - * + * + * This method internally calls {@link SAXParserFactory}{@code .newInstance().newSAXParser().getXMLReader()} or {@link XMLReaderFactory#createXMLReader()}. + * Be sure to configure returned reader if the default configuration does not suit you. Consider setting the following properties: + * + * <pre> + * reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + * reader.setFeature("http://xml.org/sax/features/external-general-entities", false); + * reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + * </pre> + * * @param validating * DOCUMENT ME! - * + * * @return DOCUMENT ME! - * + * * @throws SAXException * DOCUMENT ME! */ @@ -125,12 +136,12 @@ public static XMLReader createXMLReader(boolean validating) * This method attempts to use JAXP to locate the SAX2 XMLReader * implementation. This method uses reflection to avoid being dependent * directly on the JAXP classes. - * + * * @param validating * DOCUMENT ME! * @param namespaceAware * DOCUMENT ME! - * + * * @return DOCUMENT ME! */ protected static XMLReader createXMLReaderViaJAXP(boolean validating, @@ -176,24 +187,24 @@ protected static boolean isVerboseErrorReporting() { * Redistribution and use of this software and associated documentation * ("Software"), with or without modification, are permitted provided that the * following conditions are met: - * + * * 1. Redistributions of source code must retain copyright statements and * notices. Redistributions must also contain a copy of this document. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * 3. The name "DOM4J" must not be used to endorse or promote products derived * from this Software without prior written permission of MetaStuff, Ltd. For * written permission, please contact dom4j-info@metastuff.com. - * + * * 4. Products derived from this Software may not be called "DOM4J" nor may * "DOM4J" appear in their names without prior written permission of MetaStuff, * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd. - * + * * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org - * + * * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -205,6 +216,6 @@ protected static boolean isVerboseErrorReporting() { * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. - * + * * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved. */ diff --git a/src/main/java/org/dom4j/io/SAXReader.java b/src/main/java/org/dom4j/io/SAXReader.java index 6bb3d926..73660abf 100644 --- a/src/main/java/org/dom4j/io/SAXReader.java +++ b/src/main/java/org/dom4j/io/SAXReader.java @@ -30,32 +30,34 @@ import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; +import javax.xml.parsers.SAXParserFactory; + /** * <code>SAXReader</code> creates a DOM4J tree from SAX parsing events. - * + * <p> * The actual SAX parser that is used by this class is configurable so you can * use your favourite SAX parser if you wish. DOM4J comes configured with its * own SAX parser so you do not need to worry about configuring the SAX parser. - * + * <p> * To explicitly configure the SAX parser that is used via Java code you can use * a constructor or use the {@link #setXMLReader(XMLReader)}or {@link * #setXMLReaderClassName(String)} methods. - * + * <p> * If the parser is not specified explicitly then the standard SAX policy of * using the <code>org.xml.sax.driver</code> system property is used to * determine the implementation class of {@link XMLReader}. - * + * <p> * If the <code>org.xml.sax.driver</code> system property is not defined then * JAXP is used via reflection (so that DOM4J is not explicitly dependent on the * JAXP classes) to load the JAXP configured SAXParser. If there is any error * creating a JAXP SAXParser an informational message is output and then the * default (Aelfred) SAX parser is used instead. - * + * <p> * If you are trying to use JAXP to explicitly set your SAX parser and are * experiencing problems, you can turn on verbose error reporting by defining * the system property <code>org.dom4j.verbose</code> to be "true" which will * output a more detailed description of why JAXP could not find a SAX parser - * + * <p> * For more information on JAXP please go to <a * href="http://java.sun.com/xml/">Sun's Java & XML site </a> * @@ -63,932 +65,946 @@ * @version $Revision: 1.58 $ */ public class SAXReader { - private static final String SAX_STRING_INTERNING = - "http://xml.org/sax/features/string-interning"; - private static final String SAX_DECL_HANDLER = - "http://xml.org/sax/properties/declaration-handler"; - private static final String SAX_LEXICAL_HANDLER = - "http://xml.org/sax/properties/lexical-handler"; - private static final String SAX_LEXICALHANDLER = - "http://xml.org/sax/handlers/LexicalHandler"; - - /** <code>DocumentFactory</code> used to create new document objects */ - private DocumentFactory factory; - - /** <code>XMLReader</code> used to parse the SAX events */ - private XMLReader xmlReader; - - /** Whether validation should occur */ - private boolean validating; - - /** DispatchHandler to call when each <code>Element</code> is encountered */ - private DispatchHandler dispatchHandler; - - /** ErrorHandler class to use */ - private ErrorHandler errorHandler; - - /** The entity resolver */ - private EntityResolver entityResolver; - - /** Should element & attribute names and namespace URIs be interned? */ - private boolean stringInternEnabled = true; - - /** Should internal DTD declarations be expanded into a List in the DTD */ - private boolean includeInternalDTDDeclarations = false; - - /** Should external DTD declarations be expanded into a List in the DTD */ - private boolean includeExternalDTDDeclarations = false; - - /** Whether adjacent text nodes should be merged */ - private boolean mergeAdjacentText = false; - - /** Holds value of property stripWhitespaceText. */ - private boolean stripWhitespaceText = false; - - /** Should we ignore comments */ - private boolean ignoreComments = false; - - /** Encoding of InputSource - null means system default encoding */ - private String encoding = null; - - // private boolean includeExternalGeneralEntities = false; - // private boolean includeExternalParameterEntities = false; - - /** The SAX filter used to filter SAX events */ - private XMLFilter xmlFilter; - - public SAXReader() { - } - - public SAXReader(boolean validating) { - this.validating = validating; - } - - public SAXReader(DocumentFactory factory) { - this.factory = factory; - } - - public SAXReader(DocumentFactory factory, boolean validating) { - this.factory = factory; - this.validating = validating; - } - - public SAXReader(XMLReader xmlReader) { - this.xmlReader = xmlReader; - } - - public SAXReader(XMLReader xmlReader, boolean validating) { - this.xmlReader = xmlReader; - this.validating = validating; - } - - public SAXReader(String xmlReaderClassName) throws SAXException { - if (xmlReaderClassName != null) { - this.xmlReader = XMLReaderFactory - .createXMLReader(xmlReaderClassName); + private static final String SAX_STRING_INTERNING = + "http://xml.org/sax/features/string-interning"; + private static final String SAX_DECL_HANDLER = + "http://xml.org/sax/properties/declaration-handler"; + private static final String SAX_LEXICAL_HANDLER = + "http://xml.org/sax/properties/lexical-handler"; + private static final String SAX_LEXICALHANDLER = + "http://xml.org/sax/handlers/LexicalHandler"; + + /** + * <code>DocumentFactory</code> used to create new document objects + */ + private DocumentFactory factory; + + /** + * <code>XMLReader</code> used to parse the SAX events + */ + private XMLReader xmlReader; + + /** + * Whether validation should occur + */ + private boolean validating; + + /** + * DispatchHandler to call when each <code>Element</code> is encountered + */ + private DispatchHandler dispatchHandler; + + /** + * ErrorHandler class to use + */ + private ErrorHandler errorHandler; + + /** + * The entity resolver + */ + private EntityResolver entityResolver; + + /** + * Should element & attribute names and namespace URIs be interned? + */ + private boolean stringInternEnabled = true; + + /** + * Should internal DTD declarations be expanded into a List in the DTD + */ + private boolean includeInternalDTDDeclarations = false; + + /** + * Should external DTD declarations be expanded into a List in the DTD + */ + private boolean includeExternalDTDDeclarations = false; + + /** + * Whether adjacent text nodes should be merged + */ + private boolean mergeAdjacentText = false; + + /** + * Holds value of property stripWhitespaceText. + */ + private boolean stripWhitespaceText = false; + + /** + * Should we ignore comments + */ + private boolean ignoreComments = false; + + /** + * Encoding of InputSource - null means system default encoding + */ + private String encoding = null; + + // private boolean includeExternalGeneralEntities = false; + // private boolean includeExternalParameterEntities = false; + + /** + * The SAX filter used to filter SAX events + * + * @since 2.1.2 + */ + private XMLFilter xmlFilter; + + public static SAXReader createDefault() { + SAXReader reader = new SAXReader(); + try { + reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + reader.setFeature("http://xml.org/sax/features/external-general-entities", false); + reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + } catch (SAXException e) { + // nothing to do, incompatible reader + } + return reader; + } + + /** + * This method internally calls {@link SAXParserFactory}{@code .newInstance().newSAXParser().getXMLReader()} or {@link XMLReaderFactory#createXMLReader()}. + * Be sure to configure returned reader if the default configuration does not suit you. Consider setting the following properties: + * + * <pre> + * reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + * reader.setFeature("http://xml.org/sax/features/external-general-entities", false); + * reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + * </pre> + */ + public SAXReader() { + } + + /** + * This method internally calls {@link SAXParserFactory}{@code .newInstance().newSAXParser().getXMLReader()} or {@link XMLReaderFactory#createXMLReader()}. + * Be sure to configure returned reader if the default configuration does not suit you. Consider setting the following properties: + * + * <pre> + * reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + * reader.setFeature("http://xml.org/sax/features/external-general-entities", false); + * reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + * </pre> + * + * @param validating + */ + public SAXReader(boolean validating) { + this.validating = validating; + } + + /** + * This method internally calls {@link SAXParserFactory}{@code .newInstance().newSAXParser().getXMLReader()} or {@link XMLReaderFactory#createXMLReader()}. + * Be sure to configure returned reader if the default configuration does not suit you. Consider setting the following properties: + * + * <pre> + * reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + * reader.setFeature("http://xml.org/sax/features/external-general-entities", false); + * reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + * </pre> + * + * @param factory + */ + public SAXReader(DocumentFactory factory) { + this.factory = factory; + } + + /** + * This method internally calls {@link SAXParserFactory}{@code .newInstance().newSAXParser().getXMLReader()} or {@link XMLReaderFactory#createXMLReader()}. + * Be sure to configure returned reader if the default configuration does not suit you. Consider setting the following properties: + * + * <pre> + * reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + * reader.setFeature("http://xml.org/sax/features/external-general-entities", false); + * reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + * </pre> + * + * @param factory + * @param validating + */ + public SAXReader(DocumentFactory factory, boolean validating) { + this.factory = factory; + this.validating = validating; + } + + public SAXReader(XMLReader xmlReader) { + this.xmlReader = xmlReader; + } + + public SAXReader(XMLReader xmlReader, boolean validating) { + this.xmlReader = xmlReader; + this.validating = validating; + } + + public SAXReader(String xmlReaderClassName) throws SAXException { + if (xmlReaderClassName != null) { + this.xmlReader = XMLReaderFactory + .createXMLReader(xmlReaderClassName); + } + } + + public SAXReader(String xmlReaderClassName, boolean validating) + throws SAXException { + if (xmlReaderClassName != null) { + this.xmlReader = XMLReaderFactory + .createXMLReader(xmlReaderClassName); + } + + this.validating = validating; + } + + /** + * Allows a SAX property to be set on the underlying SAX parser. This can be + * useful to set parser-specific properties such as the location of schema + * or DTD resources. Though use this method with caution as it has the + * possibility of breaking the standard behaviour. An alternative to calling + * this method is to correctly configure an XMLReader object instance and + * call the {@link #setXMLReader(XMLReader)}method + * + * @param name is the SAX property name + * @param value is the value of the SAX property + * @throws SAXException if the XMLReader could not be created or the property could + * not be changed. + */ + public void setProperty(String name, Object value) throws SAXException { + getXMLReader().setProperty(name, value); + } + + /** + * Sets a SAX feature on the underlying SAX parser. This can be useful to + * set parser-specific features. Though use this method with caution as it + * has the possibility of breaking the standard behaviour. An alternative to + * calling this method is to correctly configure an XMLReader object + * instance and call the {@link #setXMLReader(XMLReader)}method + * + * @param name is the SAX feature name + * @param value is the value of the SAX feature + * @throws SAXException if the XMLReader could not be created or the feature could + * not be changed. + */ + public void setFeature(String name, boolean value) throws SAXException { + getXMLReader().setFeature(name, value); + } + + /** + * <p> + * Reads a Document from the given <code>File</code> + * </p> + * + * @param file is the <code>File</code> to read from. + * @return the newly created Document instance + * @throws DocumentException if an error occurs during parsing. + */ + public Document read(File file) throws DocumentException { + try { + /* + * We cannot convert the file to an URL because if the filename + * contains '#' characters, there will be problems with the URL in + * the InputSource (because a URL like + * http://myhost.com/index#anchor is treated the same as + * http://myhost.com/index) Thanks to Christian Oetterli + */ + InputSource source = new InputSource(new FileInputStream(file)); + if (this.encoding != null) { + source.setEncoding(this.encoding); + } + String path = file.getAbsolutePath(); + + if (path != null) { + // Code taken from Ant FileUtils + StringBuffer sb = new StringBuffer("file://"); + + // add an extra slash for filesystems with drive-specifiers + if (!path.startsWith(File.separator)) { + sb.append("/"); } - } - public SAXReader(String xmlReaderClassName, boolean validating) - throws SAXException { - if (xmlReaderClassName != null) { - this.xmlReader = XMLReaderFactory - .createXMLReader(xmlReaderClassName); + path = path.replace('\\', '/'); + sb.append(path); + + source.setSystemId(sb.toString()); + } + + return read(source); + } catch (FileNotFoundException e) { + throw new DocumentException(e.getMessage(), e); + } + } + + /** + * <p> + * Reads a Document from the given <code>URL</code> using SAX + * </p> + * + * @param url <code>URL</code> to read from. + * @return the newly created Document instance + * @throws DocumentException if an error occurs during parsing. + */ + public Document read(URL url) throws DocumentException { + String systemID = url.toExternalForm(); + + InputSource source = new InputSource(systemID); + if (this.encoding != null) { + source.setEncoding(this.encoding); + } + + return read(source); + } + + /** + * <p> + * Reads a Document from the given URL or filename using SAX. + * </p> + * + * <p> + * If the systemId contains a <code>':'</code> character then it is + * assumed to be a URL otherwise its assumed to be a file name. If you want + * finer grained control over this mechansim then please explicitly pass in + * either a {@link URL}or a {@link File}instance instead of a {@link + * String} to denote the source of the document. + * </p> + * + * @param systemId is a URL for a document or a file name. + * @return the newly created Document instance + * @throws DocumentException if an error occurs during parsing. + */ + public Document read(String systemId) throws DocumentException { + InputSource source = new InputSource(systemId); + if (this.encoding != null) { + source.setEncoding(this.encoding); + } + + return read(source); + } + + /** + * <p> + * Reads a Document from the given stream using SAX + * </p> + * + * @param in <code>InputStream</code> to read from. + * @return the newly created Document instance + * @throws DocumentException if an error occurs during parsing. + */ + public Document read(InputStream in) throws DocumentException { + InputSource source = new InputSource(in); + if (this.encoding != null) { + source.setEncoding(this.encoding); + } + + return read(source); + } + + /** + * Reads a Document from the given <code>Reader</code> using SAX + * + * @param reader is the reader for the input + * @return the newly created Document instance + * @throws DocumentException if an error occurs during parsing. + */ + public Document read(Reader reader) throws DocumentException { + InputSource source = new InputSource(reader); + if (this.encoding != null) { + source.setEncoding(this.encoding); + } + + return read(source); + } + + /** + * <p> + * Reads a Document from the given stream using SAX + * </p> + * + * @param in <code>InputStream</code> to read from. + * @param systemId is the URI for the input + * @return the newly created Document instance + * @throws DocumentException if an error occurs during parsing. + */ + public Document read(InputStream in, String systemId) + throws DocumentException { + InputSource source = new InputSource(in); + source.setSystemId(systemId); + if (this.encoding != null) { + source.setEncoding(this.encoding); + } + + return read(source); + } + + /** + * <p> + * Reads a Document from the given <code>Reader</code> using SAX + * </p> + * + * @param reader is the reader for the input + * @param systemId is the URI for the input + * @return the newly created Document instance + * @throws DocumentException if an error occurs during parsing. + */ + public Document read(Reader reader, String systemId) + throws DocumentException { + InputSource source = new InputSource(reader); + source.setSystemId(systemId); + if (this.encoding != null) { + source.setEncoding(this.encoding); + } + + return read(source); + } + + /** + * <p> + * Reads a Document from the given <code>InputSource</code> using SAX + * </p> + * + * @param in <code>InputSource</code> to read from. + * @return the newly created Document instance + * @throws DocumentException if an error occurs during parsing. + */ + public Document read(InputSource in) throws DocumentException { + try { + XMLReader reader = getXMLReader(); + + reader = installXMLFilter(reader); + + EntityResolver thatEntityResolver = this.entityResolver; + + if (thatEntityResolver == null) { + thatEntityResolver = createDefaultEntityResolver(in + .getSystemId()); + this.entityResolver = thatEntityResolver; + } + + reader.setEntityResolver(thatEntityResolver); + + SAXContentHandler contentHandler = createContentHandler(reader); + contentHandler.setEntityResolver(thatEntityResolver); + contentHandler.setInputSource(in); + + boolean internal = isIncludeInternalDTDDeclarations(); + boolean external = isIncludeExternalDTDDeclarations(); + + contentHandler.setIncludeInternalDTDDeclarations(internal); + contentHandler.setIncludeExternalDTDDeclarations(external); + contentHandler.setMergeAdjacentText(isMergeAdjacentText()); + contentHandler.setStripWhitespaceText(isStripWhitespaceText()); + contentHandler.setIgnoreComments(isIgnoreComments()); + reader.setContentHandler(contentHandler); + + configureReader(reader, contentHandler); + + reader.parse(in); + + return contentHandler.getDocument(); + } catch (Exception e) { + if (e instanceof SAXParseException) { + // e.printStackTrace(); + SAXParseException parseException = (SAXParseException) e; + String systemId = parseException.getSystemId(); + + if (systemId == null) { + systemId = ""; } - this.validating = validating; - } - - /** - * Allows a SAX property to be set on the underlying SAX parser. This can be - * useful to set parser-specific properties such as the location of schema - * or DTD resources. Though use this method with caution as it has the - * possibility of breaking the standard behaviour. An alternative to calling - * this method is to correctly configure an XMLReader object instance and - * call the {@link #setXMLReader(XMLReader)}method - * - * @param name - * is the SAX property name - * @param value - * is the value of the SAX property - * - * @throws SAXException - * if the XMLReader could not be created or the property could - * not be changed. - */ - public void setProperty(String name, Object value) throws SAXException { - getXMLReader().setProperty(name, value); - } - - /** - * Sets a SAX feature on the underlying SAX parser. This can be useful to - * set parser-specific features. Though use this method with caution as it - * has the possibility of breaking the standard behaviour. An alternative to - * calling this method is to correctly configure an XMLReader object - * instance and call the {@link #setXMLReader(XMLReader)}method - * - * @param name - * is the SAX feature name - * @param value - * is the value of the SAX feature - * - * @throws SAXException - * if the XMLReader could not be created or the feature could - * not be changed. - */ - public void setFeature(String name, boolean value) throws SAXException { - getXMLReader().setFeature(name, value); - } - - /** - * <p> - * Reads a Document from the given <code>File</code> - * </p> - * - * @param file - * is the <code>File</code> to read from. - * - * @return the newly created Document instance - * - * @throws DocumentException - * if an error occurs during parsing. - */ - public Document read(File file) throws DocumentException { - try { - /* - * We cannot convert the file to an URL because if the filename - * contains '#' characters, there will be problems with the URL in - * the InputSource (because a URL like - * http://myhost.com/index#anchor is treated the same as - * http://myhost.com/index) Thanks to Christian Oetterli - */ - InputSource source = new InputSource(new FileInputStream(file)); - if (this.encoding != null) { - source.setEncoding(this.encoding); - } - String path = file.getAbsolutePath(); - - if (path != null) { - // Code taken from Ant FileUtils - StringBuffer sb = new StringBuffer("file://"); - - // add an extra slash for filesystems with drive-specifiers - if (!path.startsWith(File.separator)) { - sb.append("/"); - } - - path = path.replace('\\', '/'); - sb.append(path); - - source.setSystemId(sb.toString()); - } - - return read(source); - } catch (FileNotFoundException e) { - throw new DocumentException(e.getMessage(), e); + String message = "Error on line " + + parseException.getLineNumber() + " of document " + + systemId + " : " + parseException.getMessage(); + + throw new DocumentException(message, e); + } else { + throw new DocumentException(e.getMessage(), e); + } + } + } + + // Properties + // ------------------------------------------------------------------------- + + /** + * DOCUMENT ME! + * + * @return the validation mode, true if validating will be done otherwise + * false. + */ + public boolean isValidating() { + return validating; + } + + /** + * Sets the validation mode. + * + * @param validation indicates whether or not validation should occur. + */ + public void setValidation(boolean validation) { + this.validating = validation; + } + + /** + * DOCUMENT ME! + * + * @return whether internal DTD declarations should be expanded into the + * DocumentType object or not. + */ + public boolean isIncludeInternalDTDDeclarations() { + return includeInternalDTDDeclarations; + } + + /** + * Sets whether internal DTD declarations should be expanded into the + * DocumentType object or not. + * + * @param include whether or not DTD declarations should be expanded and + * included into the DocumentType object. + */ + public void setIncludeInternalDTDDeclarations(boolean include) { + this.includeInternalDTDDeclarations = include; + } + + /** + * DOCUMENT ME! + * + * @return whether external DTD declarations should be expanded into the + * DocumentType object or not. + */ + public boolean isIncludeExternalDTDDeclarations() { + return includeExternalDTDDeclarations; + } + + /** + * Sets whether DTD external declarations should be expanded into the + * DocumentType object or not. + * + * @param include whether or not DTD declarations should be expanded and + * included into the DocumentType object. + */ + public void setIncludeExternalDTDDeclarations(boolean include) { + this.includeExternalDTDDeclarations = include; + } + + /** + * Sets whether String interning is enabled or disabled for element & + * attribute names and namespace URIs. This proprety is enabled by default. + * + * @return DOCUMENT ME! + */ + public boolean isStringInternEnabled() { + return stringInternEnabled; + } + + /** + * Sets whether String interning is enabled or disabled for element & + * attribute names and namespace URIs + * + * @param stringInternEnabled DOCUMENT ME! + */ + public void setStringInternEnabled(boolean stringInternEnabled) { + this.stringInternEnabled = stringInternEnabled; + } + + /** + * Returns whether adjacent text nodes should be merged together. + * + * @return Value of property mergeAdjacentText. + */ + public boolean isMergeAdjacentText() { + return mergeAdjacentText; + } + + /** + * Sets whether or not adjacent text nodes should be merged together when + * parsing. + * + * @param mergeAdjacentText New value of property mergeAdjacentText. + */ + public void setMergeAdjacentText(boolean mergeAdjacentText) { + this.mergeAdjacentText = mergeAdjacentText; + } + + /** + * Sets whether whitespace between element start and end tags should be + * ignored + * + * @return Value of property stripWhitespaceText. + */ + public boolean isStripWhitespaceText() { + return stripWhitespaceText; + } + + /** + * Sets whether whitespace between element start and end tags should be + * ignored. + * + * @param stripWhitespaceText New value of property stripWhitespaceText. + */ + public void setStripWhitespaceText(boolean stripWhitespaceText) { + this.stripWhitespaceText = stripWhitespaceText; + } + + /** + * Returns whether we should ignore comments or not. + * + * @return boolean + */ + public boolean isIgnoreComments() { + return ignoreComments; + } + + /** + * Sets whether we should ignore comments or not. + * + * @param ignoreComments whether we should ignore comments or not. + */ + public void setIgnoreComments(boolean ignoreComments) { + this.ignoreComments = ignoreComments; + } + + /** + * DOCUMENT ME! + * + * @return the <code>DocumentFactory</code> used to create document + * objects + */ + public DocumentFactory getDocumentFactory() { + if (factory == null) { + factory = DocumentFactory.getInstance(); + } + + return factory; + } + + /** + * <p> + * This sets the <code>DocumentFactory</code> used to create new + * documents. This method allows the building of custom DOM4J tree objects + * to be implemented easily using a custom derivation of + * {@link DocumentFactory} + * </p> + * + * @param documentFactory <code>DocumentFactory</code> used to create DOM4J objects + */ + public void setDocumentFactory(DocumentFactory documentFactory) { + this.factory = documentFactory; + } + + /** + * DOCUMENT ME! + * + * @return the <code>ErrorHandler</code> used by SAX + */ + public ErrorHandler getErrorHandler() { + return errorHandler; + } + + /** + * Sets the <code>ErrorHandler</code> used by the SAX + * <code>XMLReader</code>. + * + * @param errorHandler is the <code>ErrorHandler</code> used by SAX + */ + public void setErrorHandler(ErrorHandler errorHandler) { + this.errorHandler = errorHandler; + } + + /** + * Returns the current entity resolver used to resolve entities + * + * @return DOCUMENT ME! + */ + public EntityResolver getEntityResolver() { + return entityResolver; + } + + /** + * Sets the entity resolver used to resolve entities. + * + * @param entityResolver DOCUMENT ME! + */ + public void setEntityResolver(EntityResolver entityResolver) { + this.entityResolver = entityResolver; + } + + /** + * DOCUMENT ME! + * + * @return the <code>XMLReader</code> used to parse SAX events + * @throws SAXException DOCUMENT ME! + */ + public XMLReader getXMLReader() throws SAXException { + if (xmlReader == null) { + xmlReader = createXMLReader(); + } + + return xmlReader; + } + + /** + * Sets the <code>XMLReader</code> used to parse SAX events + * + * @param reader is the <code>XMLReader</code> to parse SAX events + */ + public void setXMLReader(XMLReader reader) { + this.xmlReader = reader; + } + + /** + * Returns encoding used for InputSource (null means system default + * encoding) + * + * @return encoding used for InputSource + */ + public String getEncoding() { + return encoding; + } + + /** + * Sets encoding used for InputSource (null means system default encoding) + * + * @param encoding is encoding used for InputSource + */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** + * Sets the class name of the <code>XMLReader</code> to be used to parse + * SAX events. + * + * @param xmlReaderClassName is the class name of the <code>XMLReader</code> to parse SAX + * events + * @throws SAXException DOCUMENT ME! + */ + public void setXMLReaderClassName(String xmlReaderClassName) + throws SAXException { + setXMLReader(XMLReaderFactory.createXMLReader(xmlReaderClassName)); + } + + /** + * Adds the <code>ElementHandler</code> to be called when the specified + * path is encounted. + * + * @param path is the path to be handled + * @param handler is the <code>ElementHandler</code> to be called by the event + * based processor. + */ + public void addHandler(String path, ElementHandler handler) { + getDispatchHandler().addHandler(path, handler); + } + + /** + * Removes the <code>ElementHandler</code> from the event based processor, + * for the specified path. + * + * @param path is the path to remove the <code>ElementHandler</code> for. + */ + public void removeHandler(String path) { + getDispatchHandler().removeHandler(path); + } + + /** + * When multiple <code>ElementHandler</code> instances have been + * registered, this will set a default <code>ElementHandler</code> to be + * called for any path which does <b>NOT </b> have a handler registered. + * + * @param handler is the <code>ElementHandler</code> to be called by the event + * based processor. + */ + public void setDefaultHandler(ElementHandler handler) { + getDispatchHandler().setDefaultHandler(handler); + } + + /** + * This method clears out all the existing handlers and default handler + * setting things back as if no handler existed. Useful when reusing an + * object instance. + */ + public void resetHandlers() { + getDispatchHandler().resetHandlers(); + } + + /** + * Returns the SAX filter being used to filter SAX events. + * + * @return the SAX filter being used or null if no SAX filter is installed + */ + public XMLFilter getXMLFilter() { + return xmlFilter; + } + + /** + * Sets the SAX filter to be used when filtering SAX events + * + * @param filter is the SAX filter to use or null to disable filtering + */ + public void setXMLFilter(XMLFilter filter) { + this.xmlFilter = filter; + } + + // Implementation methods + // ------------------------------------------------------------------------- + + /** + * Installs any XMLFilter objects required to allow the SAX event stream to + * be filtered and preprocessed before it gets to dom4j. + * + * @param reader DOCUMENT ME! + * @return the new XMLFilter if applicable or the original XMLReader if no + * filter is being used. + */ + protected XMLReader installXMLFilter(XMLReader reader) { + XMLFilter filter = getXMLFilter(); + + if (filter != null) { + // find the root XMLFilter + XMLFilter root = filter; + + while (true) { + XMLReader parent = root.getParent(); + + if (parent instanceof XMLFilter) { + root = (XMLFilter) parent; + } else { + break; } + } + + root.setParent(reader); + + return filter; } - /** - * <p> - * Reads a Document from the given <code>URL</code> using SAX - * </p> - * - * @param url - * <code>URL</code> to read from. - * - * @return the newly created Document instance - * - * @throws DocumentException - * if an error occurs during parsing. - */ - public Document read(URL url) throws DocumentException { - String systemID = url.toExternalForm(); - - InputSource source = new InputSource(systemID); - if (this.encoding != null) { - source.setEncoding(this.encoding); - } + return reader; + } - return read(source); - } - - /** - * <p> - * Reads a Document from the given URL or filename using SAX. - * </p> - * - * <p> - * If the systemId contains a <code>':'</code> character then it is - * assumed to be a URL otherwise its assumed to be a file name. If you want - * finer grained control over this mechansim then please explicitly pass in - * either a {@link URL}or a {@link File}instance instead of a {@link - * String} to denote the source of the document. - * </p> - * - * @param systemId - * is a URL for a document or a file name. - * - * @return the newly created Document instance - * - * @throws DocumentException - * if an error occurs during parsing. - */ - public Document read(String systemId) throws DocumentException { - InputSource source = new InputSource(systemId); - if (this.encoding != null) { - source.setEncoding(this.encoding); - } - - return read(source); - } - - /** - * <p> - * Reads a Document from the given stream using SAX - * </p> - * - * @param in - * <code>InputStream</code> to read from. - * - * @return the newly created Document instance - * - * @throws DocumentException - * if an error occurs during parsing. - */ - public Document read(InputStream in) throws DocumentException { - InputSource source = new InputSource(in); - if (this.encoding != null) { - source.setEncoding(this.encoding); - } - - return read(source); - } - - /** - * Reads a Document from the given <code>Reader</code> using SAX - * - * @param reader - * is the reader for the input - * - * @return the newly created Document instance - * - * @throws DocumentException - * if an error occurs during parsing. - */ - public Document read(Reader reader) throws DocumentException { - InputSource source = new InputSource(reader); - if (this.encoding != null) { - source.setEncoding(this.encoding); - } - - return read(source); - } - - /** - * <p> - * Reads a Document from the given stream using SAX - * </p> - * - * @param in - * <code>InputStream</code> to read from. - * @param systemId - * is the URI for the input - * - * @return the newly created Document instance - * - * @throws DocumentException - * if an error occurs during parsing. - */ - public Document read(InputStream in, String systemId) - throws DocumentException { - InputSource source = new InputSource(in); - source.setSystemId(systemId); - if (this.encoding != null) { - source.setEncoding(this.encoding); - } - - return read(source); - } - - /** - * <p> - * Reads a Document from the given <code>Reader</code> using SAX - * </p> - * - * @param reader - * is the reader for the input - * @param systemId - * is the URI for the input - * - * @return the newly created Document instance - * - * @throws DocumentException - * if an error occurs during parsing. - */ - public Document read(Reader reader, String systemId) - throws DocumentException { - InputSource source = new InputSource(reader); - source.setSystemId(systemId); - if (this.encoding != null) { - source.setEncoding(this.encoding); - } - - return read(source); - } - - /** - * <p> - * Reads a Document from the given <code>InputSource</code> using SAX - * </p> - * - * @param in - * <code>InputSource</code> to read from. - * - * @return the newly created Document instance - * - * @throws DocumentException - * if an error occurs during parsing. - */ - public Document read(InputSource in) throws DocumentException { - try { - XMLReader reader = getXMLReader(); - - reader = installXMLFilter(reader); - - EntityResolver thatEntityResolver = this.entityResolver; - - if (thatEntityResolver == null) { - thatEntityResolver = createDefaultEntityResolver(in - .getSystemId()); - this.entityResolver = thatEntityResolver; - } - - reader.setEntityResolver(thatEntityResolver); - - SAXContentHandler contentHandler = createContentHandler(reader); - contentHandler.setEntityResolver(thatEntityResolver); - contentHandler.setInputSource(in); - - boolean internal = isIncludeInternalDTDDeclarations(); - boolean external = isIncludeExternalDTDDeclarations(); - - contentHandler.setIncludeInternalDTDDeclarations(internal); - contentHandler.setIncludeExternalDTDDeclarations(external); - contentHandler.setMergeAdjacentText(isMergeAdjacentText()); - contentHandler.setStripWhitespaceText(isStripWhitespaceText()); - contentHandler.setIgnoreComments(isIgnoreComments()); - reader.setContentHandler(contentHandler); - - configureReader(reader, contentHandler); - - reader.parse(in); - - return contentHandler.getDocument(); - } catch (Exception e) { - if (e instanceof SAXParseException) { - // e.printStackTrace(); - SAXParseException parseException = (SAXParseException) e; - String systemId = parseException.getSystemId(); - - if (systemId == null) { - systemId = ""; - } - - String message = "Error on line " - + parseException.getLineNumber() + " of document " - + systemId + " : " + parseException.getMessage(); - - throw new DocumentException(message, e); - } else { - throw new DocumentException(e.getMessage(), e); - } + protected DispatchHandler getDispatchHandler() { + if (dispatchHandler == null) { + dispatchHandler = new DispatchHandler(); + } + + return dispatchHandler; + } + + protected void setDispatchHandler(DispatchHandler dispatchHandler) { + this.dispatchHandler = dispatchHandler; + } + + /** + * Factory Method to allow alternate methods of creating and configuring + * XMLReader objects + * + * @return DOCUMENT ME! + * @throws SAXException DOCUMENT ME! + */ + protected XMLReader createXMLReader() throws SAXException { + return SAXHelper.createXMLReader(isValidating()); + } + + /** + * Configures the XMLReader before use + * + * @param reader DOCUMENT ME! + * @param handler DOCUMENT ME! + * @throws DocumentException DOCUMENT ME! + */ + protected void configureReader(XMLReader reader, DefaultHandler handler) + throws DocumentException { + // configure lexical handling + SAXHelper.setParserProperty(reader, SAX_LEXICALHANDLER, handler); + + // try alternate property just in case + SAXHelper.setParserProperty(reader, SAX_LEXICAL_HANDLER, handler); + + // register the DeclHandler + if (includeInternalDTDDeclarations || includeExternalDTDDeclarations) { + SAXHelper.setParserProperty(reader, SAX_DECL_HANDLER, handler); + } + + // string interning + SAXHelper.setParserFeature(reader, SAX_STRING_INTERNING, + isStringInternEnabled()); + + try { + // configure validation support + reader.setFeature("http://xml.org/sax/features/validation", + isValidating()); + + if (errorHandler != null) { + reader.setErrorHandler(errorHandler); + } else { + reader.setErrorHandler(handler); + } + } catch (Exception e) { + if (isValidating()) { + throw new DocumentException("Validation not supported for" + + " XMLReader: " + reader, e); + } + } + } + + /** + * Factory Method to allow user derived SAXContentHandler objects to be used + * + * @param reader DOCUMENT ME! + * @return DOCUMENT ME! + */ + protected SAXContentHandler createContentHandler(XMLReader reader) { + return new SAXContentHandler(getDocumentFactory(), dispatchHandler); + } + + protected EntityResolver createDefaultEntityResolver(String systemId) { + String prefix = null; + + if ((systemId != null) && (systemId.length() > 0)) { + int idx = systemId.lastIndexOf('/'); + + if (idx > 0) { + prefix = systemId.substring(0, idx + 1); + } + } + + return new SAXEntityResolver(prefix); + } + + protected static class SAXEntityResolver implements EntityResolver, + Serializable { + protected String uriPrefix; + + public SAXEntityResolver(String uriPrefix) { + this.uriPrefix = uriPrefix; + } + + public InputSource resolveEntity(String publicId, String systemId) { + // try create a relative URI reader... + if ((systemId != null) && (systemId.length() > 0)) { + if ((uriPrefix != null) && (systemId.indexOf(':') <= 0)) { + systemId = uriPrefix + systemId; } - } - - // Properties - // ------------------------------------------------------------------------- - - /** - * DOCUMENT ME! - * - * @return the validation mode, true if validating will be done otherwise - * false. - */ - public boolean isValidating() { - return validating; - } - - /** - * Sets the validation mode. - * - * @param validation - * indicates whether or not validation should occur. - */ - public void setValidation(boolean validation) { - this.validating = validation; - } + } - /** - * DOCUMENT ME! - * - * @return whether internal DTD declarations should be expanded into the - * DocumentType object or not. - */ - public boolean isIncludeInternalDTDDeclarations() { - return includeInternalDTDDeclarations; - } - - /** - * Sets whether internal DTD declarations should be expanded into the - * DocumentType object or not. - * - * @param include - * whether or not DTD declarations should be expanded and - * included into the DocumentType object. - */ - public void setIncludeInternalDTDDeclarations(boolean include) { - this.includeInternalDTDDeclarations = include; - } - - /** - * DOCUMENT ME! - * - * @return whether external DTD declarations should be expanded into the - * DocumentType object or not. - */ - public boolean isIncludeExternalDTDDeclarations() { - return includeExternalDTDDeclarations; - } - - /** - * Sets whether DTD external declarations should be expanded into the - * DocumentType object or not. - * - * @param include - * whether or not DTD declarations should be expanded and - * included into the DocumentType object. - */ - public void setIncludeExternalDTDDeclarations(boolean include) { - this.includeExternalDTDDeclarations = include; - } - - /** - * Sets whether String interning is enabled or disabled for element & - * attribute names and namespace URIs. This proprety is enabled by default. - * - * @return DOCUMENT ME! - */ - public boolean isStringInternEnabled() { - return stringInternEnabled; - } - - /** - * Sets whether String interning is enabled or disabled for element & - * attribute names and namespace URIs - * - * @param stringInternEnabled - * DOCUMENT ME! - */ - public void setStringInternEnabled(boolean stringInternEnabled) { - this.stringInternEnabled = stringInternEnabled; - } - - /** - * Returns whether adjacent text nodes should be merged together. - * - * @return Value of property mergeAdjacentText. - */ - public boolean isMergeAdjacentText() { - return mergeAdjacentText; - } - - /** - * Sets whether or not adjacent text nodes should be merged together when - * parsing. - * - * @param mergeAdjacentText - * New value of property mergeAdjacentText. - */ - public void setMergeAdjacentText(boolean mergeAdjacentText) { - this.mergeAdjacentText = mergeAdjacentText; - } - - /** - * Sets whether whitespace between element start and end tags should be - * ignored - * - * @return Value of property stripWhitespaceText. - */ - public boolean isStripWhitespaceText() { - return stripWhitespaceText; - } - - /** - * Sets whether whitespace between element start and end tags should be - * ignored. - * - * @param stripWhitespaceText - * New value of property stripWhitespaceText. - */ - public void setStripWhitespaceText(boolean stripWhitespaceText) { - this.stripWhitespaceText = stripWhitespaceText; - } - - /** - * Returns whether we should ignore comments or not. - * - * @return boolean - */ - public boolean isIgnoreComments() { - return ignoreComments; - } - - /** - * Sets whether we should ignore comments or not. - * - * @param ignoreComments - * whether we should ignore comments or not. - */ - public void setIgnoreComments(boolean ignoreComments) { - this.ignoreComments = ignoreComments; - } - - /** - * DOCUMENT ME! - * - * @return the <code>DocumentFactory</code> used to create document - * objects - */ - public DocumentFactory getDocumentFactory() { - if (factory == null) { - factory = DocumentFactory.getInstance(); - } - - return factory; - } - - /** - * <p> - * This sets the <code>DocumentFactory</code> used to create new - * documents. This method allows the building of custom DOM4J tree objects - * to be implemented easily using a custom derivation of - * {@link DocumentFactory} - * </p> - * - * @param documentFactory - * <code>DocumentFactory</code> used to create DOM4J objects - */ - public void setDocumentFactory(DocumentFactory documentFactory) { - this.factory = documentFactory; - } - - /** - * DOCUMENT ME! - * - * @return the <code>ErrorHandler</code> used by SAX - */ - public ErrorHandler getErrorHandler() { - return errorHandler; - } - - /** - * Sets the <code>ErrorHandler</code> used by the SAX - * <code>XMLReader</code>. - * - * @param errorHandler - * is the <code>ErrorHandler</code> used by SAX - */ - public void setErrorHandler(ErrorHandler errorHandler) { - this.errorHandler = errorHandler; - } - - /** - * Returns the current entity resolver used to resolve entities - * - * @return DOCUMENT ME! - */ - public EntityResolver getEntityResolver() { - return entityResolver; - } - - /** - * Sets the entity resolver used to resolve entities. - * - * @param entityResolver - * DOCUMENT ME! - */ - public void setEntityResolver(EntityResolver entityResolver) { - this.entityResolver = entityResolver; - } - - /** - * DOCUMENT ME! - * - * @return the <code>XMLReader</code> used to parse SAX events - * - * @throws SAXException - * DOCUMENT ME! - */ - public XMLReader getXMLReader() throws SAXException { - if (xmlReader == null) { - xmlReader = createXMLReader(); - } - - return xmlReader; - } - - /** - * Sets the <code>XMLReader</code> used to parse SAX events - * - * @param reader - * is the <code>XMLReader</code> to parse SAX events - */ - public void setXMLReader(XMLReader reader) { - this.xmlReader = reader; - } - - /** - * Returns encoding used for InputSource (null means system default - * encoding) - * - * @return encoding used for InputSource - * - */ - public String getEncoding() { - return encoding; - } - - /** - * Sets encoding used for InputSource (null means system default encoding) - * - * @param encoding - * is encoding used for InputSource - */ - public void setEncoding(String encoding) { - this.encoding = encoding; - } - - /** - * Sets the class name of the <code>XMLReader</code> to be used to parse - * SAX events. - * - * @param xmlReaderClassName - * is the class name of the <code>XMLReader</code> to parse SAX - * events - * - * @throws SAXException - * DOCUMENT ME! - */ - public void setXMLReaderClassName(String xmlReaderClassName) - throws SAXException { - setXMLReader(XMLReaderFactory.createXMLReader(xmlReaderClassName)); - } - - /** - * Adds the <code>ElementHandler</code> to be called when the specified - * path is encounted. - * - * @param path - * is the path to be handled - * @param handler - * is the <code>ElementHandler</code> to be called by the event - * based processor. - */ - public void addHandler(String path, ElementHandler handler) { - getDispatchHandler().addHandler(path, handler); - } - - /** - * Removes the <code>ElementHandler</code> from the event based processor, - * for the specified path. - * - * @param path - * is the path to remove the <code>ElementHandler</code> for. - */ - public void removeHandler(String path) { - getDispatchHandler().removeHandler(path); - } - - /** - * When multiple <code>ElementHandler</code> instances have been - * registered, this will set a default <code>ElementHandler</code> to be - * called for any path which does <b>NOT </b> have a handler registered. - * - * @param handler - * is the <code>ElementHandler</code> to be called by the event - * based processor. - */ - public void setDefaultHandler(ElementHandler handler) { - getDispatchHandler().setDefaultHandler(handler); - } - - /** - * This method clears out all the existing handlers and default handler - * setting things back as if no handler existed. Useful when reusing an - * object instance. - */ - public void resetHandlers() { - getDispatchHandler().resetHandlers(); - } - - /** - * Returns the SAX filter being used to filter SAX events. - * - * @return the SAX filter being used or null if no SAX filter is installed - */ - public XMLFilter getXMLFilter() { - return xmlFilter; - } - - /** - * Sets the SAX filter to be used when filtering SAX events - * - * @param filter - * is the SAX filter to use or null to disable filtering - */ - public void setXMLFilter(XMLFilter filter) { - this.xmlFilter = filter; - } - - // Implementation methods - // ------------------------------------------------------------------------- - - /** - * Installs any XMLFilter objects required to allow the SAX event stream to - * be filtered and preprocessed before it gets to dom4j. - * - * @param reader - * DOCUMENT ME! - * - * @return the new XMLFilter if applicable or the original XMLReader if no - * filter is being used. - */ - protected XMLReader installXMLFilter(XMLReader reader) { - XMLFilter filter = getXMLFilter(); - - if (filter != null) { - // find the root XMLFilter - XMLFilter root = filter; - - while (true) { - XMLReader parent = root.getParent(); - - if (parent instanceof XMLFilter) { - root = (XMLFilter) parent; - } else { - break; - } - } - - root.setParent(reader); - - return filter; - } - - return reader; - } - - protected DispatchHandler getDispatchHandler() { - if (dispatchHandler == null) { - dispatchHandler = new DispatchHandler(); - } - - return dispatchHandler; - } - - protected void setDispatchHandler(DispatchHandler dispatchHandler) { - this.dispatchHandler = dispatchHandler; - } - - /** - * Factory Method to allow alternate methods of creating and configuring - * XMLReader objects - * - * @return DOCUMENT ME! - * - * @throws SAXException - * DOCUMENT ME! - */ - protected XMLReader createXMLReader() throws SAXException { - return SAXHelper.createXMLReader(isValidating()); - } - - /** - * Configures the XMLReader before use - * - * @param reader - * DOCUMENT ME! - * @param handler - * DOCUMENT ME! - * - * @throws DocumentException - * DOCUMENT ME! - */ - protected void configureReader(XMLReader reader, DefaultHandler handler) - throws DocumentException { - // configure lexical handling - SAXHelper.setParserProperty(reader, SAX_LEXICALHANDLER, handler); - - // try alternate property just in case - SAXHelper.setParserProperty(reader, SAX_LEXICAL_HANDLER, handler); - - // register the DeclHandler - if (includeInternalDTDDeclarations || includeExternalDTDDeclarations) { - SAXHelper.setParserProperty(reader, SAX_DECL_HANDLER, handler); - } - - // string interning - SAXHelper.setParserFeature(reader, SAX_STRING_INTERNING, - isStringInternEnabled()); - - try { - // configure validation support - reader.setFeature("http://xml.org/sax/features/validation", - isValidating()); - - if (errorHandler != null) { - reader.setErrorHandler(errorHandler); - } else { - reader.setErrorHandler(handler); - } - } catch (Exception e) { - if (isValidating()) { - throw new DocumentException("Validation not supported for" - + " XMLReader: " + reader, e); - } - } - } - - /** - * Factory Method to allow user derived SAXContentHandler objects to be used - * - * @param reader - * DOCUMENT ME! - * - * @return DOCUMENT ME! - */ - protected SAXContentHandler createContentHandler(XMLReader reader) { - return new SAXContentHandler(getDocumentFactory(), dispatchHandler); - } - - protected EntityResolver createDefaultEntityResolver(String systemId) { - String prefix = null; - - if ((systemId != null) && (systemId.length() > 0)) { - int idx = systemId.lastIndexOf('/'); - - if (idx > 0) { - prefix = systemId.substring(0, idx + 1); - } - } - - return new SAXEntityResolver(prefix); - } - - protected static class SAXEntityResolver implements EntityResolver, - Serializable { - protected String uriPrefix; - - public SAXEntityResolver(String uriPrefix) { - this.uriPrefix = uriPrefix; - } - - public InputSource resolveEntity(String publicId, String systemId) { - // try create a relative URI reader... - if ((systemId != null) && (systemId.length() > 0)) { - if ((uriPrefix != null) && (systemId.indexOf(':') <= 0)) { - systemId = uriPrefix + systemId; - } - } - - return new InputSource(systemId); - } + return new InputSource(systemId); } + } } /* * Redistribution and use of this software and associated documentation * ("Software"), with or without modification, are permitted provided that the * following conditions are met: - * + * * 1. Redistributions of source code must retain copyright statements and * notices. Redistributions must also contain a copy of this document. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * 3. The name "DOM4J" must not be used to endorse or promote products derived * from this Software without prior written permission of MetaStuff, Ltd. For * written permission, please contact dom4j-info@metastuff.com. - * + * * 4. Products derived from this Software may not be called "DOM4J" nor may * "DOM4J" appear in their names without prior written permission of MetaStuff, * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd. - * + * * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org - * + * * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -1000,6 +1016,6 @@ public InputSource resolveEntity(String publicId, String systemId) { * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. - * + * * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved. */
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2