/*
* Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
*
* This software is open source.
* See the bottom of this file for the licence.
*/
package org.dom4j;
import java.io.
IOException;
import java.io.
ObjectInputStream;
import java.io.
Serializable;
import java.util.
List;
import java.util.
Map;
import org.dom4j.rule.
Pattern;
import org.dom4j.tree.
AbstractDocument;
import org.dom4j.tree.
DefaultAttribute;
import org.dom4j.tree.
DefaultCDATA;
import org.dom4j.tree.
DefaultComment;
import org.dom4j.tree.
DefaultDocument;
import org.dom4j.tree.
DefaultDocumentType;
import org.dom4j.tree.
DefaultElement;
import org.dom4j.tree.
DefaultEntity;
import org.dom4j.tree.
DefaultProcessingInstruction;
import org.dom4j.tree.
DefaultText;
import org.dom4j.tree.
QNameCache;
import org.dom4j.util.
SimpleSingleton;
import org.dom4j.util.
SingletonStrategy;
import org.dom4j.xpath.
DefaultXPath;
import org.dom4j.xpath.
XPathPattern;
import org.jaxen.
VariableContext;
/**
* <p>
* <code>DocumentFactory</code> is a collection of factory methods to allow
* easy custom building of DOM4J trees. The default tree that is built uses a
* doubly linked tree.
* </p>
*
* <p>
* The tree built allows full XPath expressions from anywhere on the tree.
* </p>
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan </a>
*/
public class
DocumentFactory implements
Serializable {
private static
SingletonStrategy singleton = null;
protected transient
QNameCache cache;
/** Default namespace prefix -> URI mappings for XPath expressions to use */
private
Map xpathNamespaceURIs;
private static
SingletonStrategy createSingleton() {
SingletonStrategy result = null;
String documentFactoryClassName;
try {
documentFactoryClassName =
System.
getProperty("org.dom4j.factory",
"org.dom4j.DocumentFactory");
} catch (
Exception e) {
documentFactoryClassName = "org.dom4j.DocumentFactory";
}
try {
String singletonClass =
System.
getProperty(
"org.dom4j.DocumentFactory.singleton.strategy",
"org.dom4j.util.SimpleSingleton");
Class clazz =
Class.
forName(
singletonClass);
result = (
SingletonStrategy)
clazz.
newInstance();
} catch (
Exception e) {
result = new
SimpleSingleton();
}
result.
setSingletonClassName(
documentFactoryClassName);
return
result;
}
public
DocumentFactory() {
init();
}
/**
* <p>
* Access to singleton implementation of DocumentFactory which is used if no
* DocumentFactory is specified when building using the standard builders.
* </p>
*
* @return the default singleon instance
*/
public static synchronized
DocumentFactory getInstance() {
if (
singleton == null) {
singleton =
createSingleton();
}
return (
DocumentFactory)
singleton.
instance();
}
// Factory methods
public
Document createDocument() {
DefaultDocument answer = new
DefaultDocument();
answer.
setDocumentFactory(this);
return
answer;
}
/**
* DOCUMENT ME!
*
* @param encoding
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @since 1.5
*/
public
Document createDocument(
String encoding) {
// to keep the DocumentFactory backwards compatible, we have to do this
// in this not so nice way, since subclasses only need to extend the
// createDocument() method.
Document answer =
createDocument();
if (
answer instanceof
AbstractDocument) {
((
AbstractDocument)
answer).
setXMLEncoding(
encoding);
}
return
answer;
}
public
Document createDocument(
Element rootElement) {
Document answer =
createDocument();
answer.
setRootElement(
rootElement);
return
answer;
}
public
DocumentType createDocType(
String name,
String publicId,
String systemId) {
return new
DefaultDocumentType(
name,
publicId,
systemId);
}
public
Element createElement(
QName qname) {
return new
DefaultElement(
qname);
}
public
Element createElement(
String name) {
return
createElement(
createQName(
name));
}
public
Element createElement(
String qualifiedName,
String namespaceURI) {
return
createElement(
createQName(
qualifiedName,
namespaceURI));
}
public
Attribute createAttribute(
Element owner,
QName qname,
String value) {
return new
DefaultAttribute(
qname,
value);
}
public
Attribute createAttribute(
Element owner,
String name,
String value) {
return
createAttribute(
owner,
createQName(
name),
value);
}
public
CDATA createCDATA(
String text) {
return new
DefaultCDATA(
text);
}
public
Comment createComment(
String text) {
return new
DefaultComment(
text);
}
public
Text createText(
String text) {
if (
text == null) {
String msg = "Adding text to an XML document must not be null";
throw new
IllegalArgumentException(
msg);
}
return new
DefaultText(
text);
}
public
Entity createEntity(
String name,
String text) {
return new
DefaultEntity(
name,
text);
}
public
Namespace createNamespace(
String prefix,
String uri) {
return
Namespace.
get(
prefix,
uri);
}
public
ProcessingInstruction createProcessingInstruction(
String target,
String data) {
return new
DefaultProcessingInstruction(
target,
data);
}
public
ProcessingInstruction createProcessingInstruction(
String target,
Map data) {
return new
DefaultProcessingInstruction(
target,
data);
}
public
QName createQName(
String localName,
Namespace namespace) {
return
cache.
get(
localName,
namespace);
}
public
QName createQName(
String localName) {
return
cache.
get(
localName);
}
public
QName createQName(
String name,
String prefix,
String uri) {
return
cache.
get(
name,
Namespace.
get(
prefix,
uri));
}
public
QName createQName(
String qualifiedName,
String uri) {
return
cache.
get(
qualifiedName,
uri);
}
/**
* <p>
* <code>createXPath</code> parses an XPath expression and creates a new
* XPath <code>XPath</code> instance.
* </p>
*
* @param xpathExpression
* is the XPath expression to create
*
* @return a new <code>XPath</code> instance
*
* @throws InvalidXPathException
* if the XPath expression is invalid
*/
public
XPath createXPath(
String xpathExpression)
throws
InvalidXPathException {
DefaultXPath xpath = new
DefaultXPath(
xpathExpression);
if (
xpathNamespaceURIs != null) {
xpath.
setNamespaceURIs(
xpathNamespaceURIs);
}
return
xpath;
}
/**
* <p>
* <code>createXPath</code> parses an XPath expression and creates a new
* XPath <code>XPath</code> instance.
* </p>
*
* @param xpathExpression
* is the XPath expression to create
* @param variableContext
* is the variable context to use when evaluating the XPath
*
* @return a new <code>XPath</code> instance
*/
public
XPath createXPath(
String xpathExpression,
VariableContext variableContext) {
XPath xpath =
createXPath(
xpathExpression);
xpath.
setVariableContext(
variableContext);
return
xpath;
}
/**
* <p>
* <code>createXPathFilter</code> parses a NodeFilter from the given XPath
* filter expression. XPath filter expressions occur within XPath
* expressions such as <code>self::node()[ filterExpression ]</code>
* </p>
*
* @param xpathFilterExpression
* is the XPath filter expression to create
* @param variableContext
* is the variable context to use when evaluating the XPath
*
* @return a new <code>NodeFilter</code> instance
*/
public
NodeFilter createXPathFilter(
String xpathFilterExpression,
VariableContext variableContext) {
XPath answer =
createXPath(
xpathFilterExpression);
// DefaultXPath answer = new DefaultXPath( xpathFilterExpression );
answer.
setVariableContext(
variableContext);
return
answer;
}
/**
* <p>
* <code>createXPathFilter</code> parses a NodeFilter from the given XPath
* filter expression. XPath 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
NodeFilter createXPathFilter(
String xpathFilterExpression) {
return
createXPath(
xpathFilterExpression);
// return new DefaultXPath( xpathFilterExpression );
}
/**
* <p>
* <code>createPattern</code> parses the given XPath expression to create
* 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
Pattern createPattern(
String xpathPattern) {
return new
XPathPattern(
xpathPattern);
}
// Properties
// -------------------------------------------------------------------------
/**
* Returns a list of all the QName instances currently used by this document
* factory
*
* @return DOCUMENT ME!
*/
public
List getQNames() {
return
cache.
getQNames();
}
/**
* DOCUMENT ME!
*
* @return the Map of namespace URIs that will be used by by XPath
* expressions to resolve namespace prefixes into namespace URIs.
* The map is keyed by namespace prefix and the value is the
* namespace URI. This value could well be null to indicate no
* namespace URIs are being mapped.
*/
public
Map getXPathNamespaceURIs() {
return
xpathNamespaceURIs;
}
/**
* Sets the namespace URIs to be used by XPath expressions created by this
* factory or by nodes associated with this factory. The keys are namespace
* prefixes and the values are namespace URIs.
*
* @param namespaceURIs
* DOCUMENT ME!
*/
public void
setXPathNamespaceURIs(
Map namespaceURIs) {
this.
xpathNamespaceURIs =
namespaceURIs;
}
// Implementation methods
// -------------------------------------------------------------------------
/**
* <p>
* <code>createSingleton</code> creates the singleton instance from the
* given class name.
* </p>
*
* @param className
* is the name of the DocumentFactory class to use
*
* @return a new singleton instance.
*/
protected static
DocumentFactory createSingleton(
String className) {
// let's try and class load an implementation?
try {
// I'll use the current class loader
// that loaded me to avoid problems in J2EE and web apps
Class theClass =
Class.
forName(
className, true,
DocumentFactory.class.
getClassLoader());
return (
DocumentFactory)
theClass.
newInstance();
} catch (
Throwable e) {
System.
out.
println("WARNING: Cannot load DocumentFactory: "
+
className);
return new
DocumentFactory();
}
}
/**
* DOCUMENT ME!
*
* @param qname
* DOCUMENT ME!
*
* @return the cached QName instance if there is one or adds the given qname
* to the cache if not
*/
protected
QName intern(
QName qname) {
return
cache.
intern(
qname);
}
/**
* Factory method to create the QNameCache. This method should be overloaded
* if you wish to use your own derivation of QName.
*
* @return DOCUMENT ME!
*/
protected
QNameCache createQNameCache() {
return new
QNameCache(this);
}
private void
readObject(
ObjectInputStream in) throws
IOException,
ClassNotFoundException {
in.
defaultReadObject();
init();
}
protected void
init() {
cache =
createQNameCache();
}
}
/*
* 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
* ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* 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.
*/