Java tutorial
/* * 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.io; import java.util.List; import org.dom4j.*; import org.dom4j.dtd.Decl; import org.dom4j.tree.NamespaceStack; import org.w3c.dom.DOMImplementation; /** * <code>DOMWriter</code> takes a DOM4J tree and outputs it as a W3C DOM * object * * @author <a href="mailto:james.strachan@metastuff.com">James Strachan </a> * @version $Revision: 1.17 $ */ public class DOMWriter { private static boolean loggedWarning = false; private static final String[] DEFAULT_DOM_DOCUMENT_CLASSES = { "org.apache.xerces.dom.DocumentImpl", // Xerces "gnu.xml.dom.DomDocument", // GNU JAXP "org.apache.crimson.tree.XmlDocument", // Crimson "com.sun.xml.tree.XmlDocument", // Sun's Project X "oracle.xml.parser.v2.XMLDocument", // Oracle V2 "oracle.xml.parser.XMLDocument", // Oracle V1 "org.dom4j.dom.DOMDocument" // Internal DOM implementation }; // the Class used to create new DOM Document instances private Class<?> domDocumentClass; /** stack of <code>Namespace</code> objects */ private NamespaceStack namespaceStack = new NamespaceStack(); public DOMWriter() { } public DOMWriter(Class<?> domDocumentClass) { this.domDocumentClass = domDocumentClass; } public Class<?> getDomDocumentClass() throws DocumentException { Class<?> result = domDocumentClass; if (result == null) { // lets try and find one in the classpath int size = DEFAULT_DOM_DOCUMENT_CLASSES.length; for (String name : DEFAULT_DOM_DOCUMENT_CLASSES) { try { result = Class.forName(name, true, DOMWriter.class.getClassLoader()); if (result != null) { break; } } catch (Exception e) { // could not load class correctly // lets carry on to the next one } } } return result; } /** * Sets the DOM {@link org.w3c.dom.Document}implementation class used by * the writer when creating DOM documents. * * @param domDocumentClass * is the Class implementing the {@link org.w3c.dom.Document} * interface */ public void setDomDocumentClass(Class<?> domDocumentClass) { this.domDocumentClass = domDocumentClass; } /** * Sets the DOM {@link org.w3c.dom.Document}implementation class name used * by the writer when creating DOM documents. * * @param name * is the name of the Class implementing the {@link * org.w3c.dom.Document} interface * * @throws DocumentException * if the class could not be loaded */ public void setDomDocumentClassName(String name) throws DocumentException { try { this.domDocumentClass = Class.forName(name, true, DOMWriter.class.getClassLoader()); } catch (Exception e) { throw new DocumentException("Could not load the DOM Document " + "class: " + name, e); } } public org.w3c.dom.Document write(Document document) throws DocumentException { if (document instanceof org.w3c.dom.Document) { return (org.w3c.dom.Document) document; } resetNamespaceStack(); org.w3c.dom.Document domDocument = createDomDocument(document); appendDOMTree(domDocument, domDocument, document.content()); namespaceStack.clear(); return domDocument; } public org.w3c.dom.Document write(Document document, org.w3c.dom.DOMImplementation domImpl) throws DocumentException { if (document instanceof org.w3c.dom.Document) { return (org.w3c.dom.Document) document; } resetNamespaceStack(); org.w3c.dom.Document domDocument = createDomDocument(document, domImpl); appendDOMTree(domDocument, domDocument, document.content()); namespaceStack.clear(); return domDocument; } protected void appendDOMTree(org.w3c.dom.Document domDocument, org.w3c.dom.Node domCurrent, List<Node> content) { for (Node node : content) { if (node instanceof Element) { appendDOMTree(domDocument, domCurrent, (Element) node); } else if (node instanceof Text) { Text text = (Text) node; appendDOMTree(domDocument, domCurrent, text.getText()); } else if (node instanceof CDATA) { appendDOMTree(domDocument, domCurrent, (CDATA) node); } else if (node instanceof Comment) { appendDOMTree(domDocument, domCurrent, (Comment) node); } else if (node instanceof Entity) { appendDOMTree(domDocument, domCurrent, (Entity) node); } else if (node instanceof ProcessingInstruction) { appendDOMTree(domDocument, domCurrent, (ProcessingInstruction) node); } } } protected void appendDOMTree(org.w3c.dom.Document domDocument, org.w3c.dom.Node domCurrent, Element element) { String elUri = element.getNamespaceURI(); String elName = element.getQualifiedName(); org.w3c.dom.Element domElement = domDocument.createElementNS(elUri, elName); int stackSize = namespaceStack.size(); // add the namespace of the element first Namespace elementNamespace = element.getNamespace(); if (isNamespaceDeclaration(elementNamespace)) { namespaceStack.push(elementNamespace); writeNamespace(domElement, elementNamespace); } // add the additional declared namespaces List<Namespace> declaredNamespaces = element.declaredNamespaces(); for (int i = 0, size = declaredNamespaces.size(); i < size; i++) { Namespace namespace = (Namespace) declaredNamespaces.get(i); if (isNamespaceDeclaration(namespace)) { namespaceStack.push(namespace); writeNamespace(domElement, namespace); } } // add the attributes for (Attribute attribute : element.attributes()) { String attUri = attribute.getNamespaceURI(); String attName = attribute.getQualifiedName(); String value = attribute.getValue(); domElement.setAttributeNS(attUri, attName, value); } // add content appendDOMTree(domDocument, domElement, element.content()); domCurrent.appendChild(domElement); while (namespaceStack.size() > stackSize) { namespaceStack.pop(); } } protected void appendDOMTree(org.w3c.dom.Document domDocument, org.w3c.dom.Node domCurrent, CDATA cdata) { org.w3c.dom.CDATASection domCDATA = domDocument.createCDATASection(cdata.getText()); domCurrent.appendChild(domCDATA); } protected void appendDOMTree(org.w3c.dom.Document domDocument, org.w3c.dom.Node domCurrent, Comment comment) { org.w3c.dom.Comment domComment = domDocument.createComment(comment.getText()); domCurrent.appendChild(domComment); } protected void appendDOMTree(org.w3c.dom.Document domDocument, org.w3c.dom.Node domCurrent, String text) { org.w3c.dom.Text domText = domDocument.createTextNode(text); domCurrent.appendChild(domText); } protected void appendDOMTree(org.w3c.dom.Document domDocument, org.w3c.dom.Node domCurrent, Entity entity) { org.w3c.dom.EntityReference domEntity = domDocument.createEntityReference(entity.getName()); domCurrent.appendChild(domEntity); } protected void appendDOMTree(org.w3c.dom.Document domDoc, org.w3c.dom.Node domCurrent, ProcessingInstruction pi) { org.w3c.dom.ProcessingInstruction domPI = domDoc.createProcessingInstruction(pi.getTarget(), pi.getText()); domCurrent.appendChild(domPI); } protected void writeNamespace(org.w3c.dom.Element domElement, Namespace namespace) { String attributeName = attributeNameForNamespace(namespace); // domElement.setAttributeNS("", attributeName, namespace.getURI()); domElement.setAttribute(attributeName, namespace.getURI()); } protected String attributeNameForNamespace(Namespace namespace) { String xmlns = "xmlns"; String prefix = namespace.getPrefix(); if (prefix.length() > 0) { return xmlns + ":" + prefix; } return xmlns; } protected org.w3c.dom.Document createDomDocument(Document document) throws DocumentException { org.w3c.dom.Document result = null; // use the given domDocumentClass (if not null) if (domDocumentClass != null) { try { result = (org.w3c.dom.Document) domDocumentClass.newInstance(); } catch (Exception e) { throw new DocumentException("Could not instantiate an instance " + "of DOM Document with class: " + domDocumentClass.getName(), e); } } else { // lets try JAXP first before using the hardcoded default parsers result = createDomDocumentViaJAXP(); if (result == null) { Class<?> theClass = getDomDocumentClass(); try { result = (org.w3c.dom.Document) theClass.newInstance(); } catch (Exception e) { throw new DocumentException("Could not instantiate an " + "instance of DOM Document " + "with class: " + theClass.getName(), e); } } } return result; } protected org.w3c.dom.Document createDomDocumentViaJAXP() throws DocumentException { try { return JAXPHelper.createDocument(false, true); } catch (Throwable e) { if (!loggedWarning) { loggedWarning = true; if (SAXHelper.isVerboseErrorReporting()) { // log all exceptions as warnings and carry // on as we have a default SAX parser we can use System.out.println("Warning: Caught exception attempting " + "to use JAXP to create a W3C DOM " + "document"); System.out.println("Warning: Exception was: " + e); e.printStackTrace(); } else { System.out.println("Warning: Error occurred using JAXP to " + "create a DOM document."); } } } return null; } protected org.w3c.dom.Document createDomDocument(Document document, DOMImplementation domImpl) throws DocumentException { String namespaceURI = null; String qualifiedName = null; org.w3c.dom.DocumentType docType = null; return domImpl.createDocument(namespaceURI, qualifiedName, docType); } protected boolean isNamespaceDeclaration(Namespace ns) { if ((ns != null) && (ns != Namespace.NO_NAMESPACE) && (ns != Namespace.XML_NAMESPACE)) { String uri = ns.getURI(); if ((uri != null) && (uri.length() > 0)) { if (!namespaceStack.contains(ns)) { return true; } } } return false; } protected void resetNamespaceStack() { namespaceStack.clear(); namespaceStack.push(Namespace.XML_NAMESPACE); } } /* * 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. */