Project dom4j 1.5.2 [5/2/05 10:13 PM]
 
Coverage - org/dom4j/io/DOMWriter.java
  /*
   * Copyright 2001-2004 (C) MetaStuff, Ltd. All Rights Reserved.
   * 
   * This software is open source. 
   * See the bottom of this file for the licence.
   * 
   * $Id: DOMWriter.java,v 1.15 2004/06/28 14:19:33 maartenc Exp $
   */
 
  package org.dom4j.io;
 
  import java.util.List;
 
  import org.dom4j.Attribute;
  import org.dom4j.CDATA;
  import org.dom4j.Comment;
  import org.dom4j.Document;
  import org.dom4j.DocumentException;
  import org.dom4j.Element;
  import org.dom4j.Entity;
  import org.dom4j.Namespace;
  import org.dom4j.ProcessingInstruction;
  import org.dom4j.Text;
  import org.dom4j.tree.NamespaceStack;
 
  /** <p><code>DOMWriter</code> takes a DOM4J tree and outputs
    * it as a W3C DOM object</p>
    *
    * @author <a href="mailto:james.strachan@metastuff.com">James Strachan</a>
    * @version $Revision: 1.15 $
    */
  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 */
2x       private NamespaceStack namespaceStack = new NamespaceStack();
 
       
2x       public DOMWriter() {
2x       }
      
0x       public DOMWriter(Class domDocumentClass) {
0x           this.domDocumentClass = domDocumentClass;
0x       }
 
      public Class getDomDocumentClass() throws DocumentException {
0x           Class result = domDocumentClass;
          
0/2 0x           if ( result == null ) {
              // lets try and find one in the classpath
0x               int size = DEFAULT_DOM_DOCUMENT_CLASSES.length;
0/2 0x               for ( int i = 0; i < size; i++ ) {
                  try {
0x                       String name = DEFAULT_DOM_DOCUMENT_CLASSES[i];
0x                       result = Class.forName( 
                          name,
                          true,
                          DOMWriter.class.getClassLoader()
                      );
0/2 0x                       if ( result != null ) {
0x                           break;
                      }
                  }
                  catch (Exception e) {
                      // could not load class correctly
                      // lets carry on to the next one
0x                   }
              }
          }
0x           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) {
0x           this.domDocumentClass = domDocumentClass;
0x       }
      
      /** Sets the DOM {@link org.w3c.dom.Document} implementation
        * class name used by the writer when creating DOM documents.
        *
        * @param className 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 className) throws DocumentException {
          try {
0x               this.domDocumentClass = Class.forName( 
                  className,
                  true,
                  DOMWriter.class.getClassLoader()
              );
          }
          catch (Exception e) {
0x               throw new DocumentException( 
                  "Could not load the DOM Document class: "  + className, e 
              );
0x           }
0x       }
 
      
      public org.w3c.dom.Document write(Document document) throws DocumentException {
1/2 2x           if ( document instanceof org.w3c.dom.Document ) {
2x               return (org.w3c.dom.Document) document;
          }
0x           resetNamespaceStack();
0x           org.w3c.dom.Document domDocument = createDomDocument(document);
0x           appendDOMTree(domDocument, domDocument, document.content());
0x           namespaceStack.clear();
0x           return domDocument;
      }
      
      public org.w3c.dom.Document write(
          Document document, 
          org.w3c.dom.DOMImplementation domImplementation
      ) throws DocumentException {
0/2 0x           if ( document instanceof org.w3c.dom.Document ) {
0x               return (org.w3c.dom.Document) document;
          }
0x           resetNamespaceStack();
0x           org.w3c.dom.Document domDocument = createDomDocument(document, domImplementation);
0x           appendDOMTree(domDocument, domDocument, document.content());
0x           namespaceStack.clear();
0x           return domDocument;
      }
      
      protected void appendDOMTree( 
          org.w3c.dom.Document domDocument, 
          org.w3c.dom.Node domCurrent,
          List content
      ) {
0x           int size = content.size();
0/2 0x           for ( int i = 0; i < size; i++ ) {
0x               Object object = content.get(i);
0/2 0x               if (object instanceof Element) {
0x                   appendDOMTree( domDocument, domCurrent, (Element) object);
              }
0/2 0x               else if ( object instanceof String ) {
0x                   appendDOMTree( domDocument, domCurrent, (String) object );
              }
0/2 0x               else if ( object instanceof Text ) {
0x                   Text text = (Text) object;
0x                   appendDOMTree( domDocument, domCurrent, text.getText() );
              }
0/2 0x               else if ( object instanceof CDATA ) {
0x                   appendDOMTree( domDocument, domCurrent, (CDATA) object );
              }
0/2 0x               else if ( object instanceof Comment ) {
0x                   appendDOMTree( domDocument, domCurrent, (Comment) object );
              }
0/2 0x               else if ( object instanceof Entity ) {
0x                   appendDOMTree( domDocument, domCurrent, (Entity) object );
              }
0/2 0x               else if ( object instanceof ProcessingInstruction ) {
0x                   appendDOMTree( domDocument, domCurrent, (ProcessingInstruction) object );
              }
          }
0x       }
          
      protected void appendDOMTree( 
          org.w3c.dom.Document domDocument, 
          org.w3c.dom.Node domCurrent,
          Element element
      ) {        
0x           String elUri = element.getNamespaceURI();
0x           String elName = element.getQualifiedName();
0x           org.w3c.dom.Element domElement = domDocument.createElementNS(elUri, elName);
          
0x           int stackSize = namespaceStack.size();
          
          // add the namespace of the element first
0x           Namespace elementNamespace = element.getNamespace();
0/2 0x           if (isNamespaceDeclaration(elementNamespace)) {
0x               namespaceStack.push(elementNamespace);
0x               writeNamespace(domElement, elementNamespace);
          }
          
          // add the additional declared namespaces
0x           List declaredNamespaces = element.declaredNamespaces();
0/2 0x           for ( int i = 0, size = declaredNamespaces.size(); i < size ; i++ ) {
0x               Namespace namespace = (Namespace) declaredNamespaces.get(i);
0/2 0x               if ( isNamespaceDeclaration( namespace ) ) {
0x                   namespaceStack.push( namespace );     
0x                   writeNamespace( domElement, namespace );
              }
          }
          
          // add the attributes
0/2 0x           for ( int i = 0, size = element.attributeCount(); i < size ; i++ ) {
0x               Attribute attribute = (Attribute) element.attribute(i);
0x               String attUri = attribute.getNamespaceURI();
0x               String attName = attribute.getQualifiedName();
0x               String value =  attribute.getValue();
0x               domElement.setAttributeNS(attUri, attName, value);
          }
 
          // add content
0x           appendDOMTree( domDocument, domElement, element.content() );
          
0x           domCurrent.appendChild( domElement );
          
0/2 0x           while ( namespaceStack.size() > stackSize ) {
0x               namespaceStack.pop();
          }
0x       }
      
      protected void appendDOMTree( 
          org.w3c.dom.Document domDocument, 
          org.w3c.dom.Node domCurrent,
          CDATA cdata
      ) {
0x           org.w3c.dom.CDATASection domCDATA = 
              domDocument.createCDATASection(cdata.getText());        
0x           domCurrent.appendChild(domCDATA);
0x       }
          
      protected void appendDOMTree( 
          org.w3c.dom.Document domDocument, 
          org.w3c.dom.Node domCurrent,
          Comment comment
      ) {
0x           org.w3c.dom.Comment domComment = 
              domDocument.createComment(comment.getText());
0x           domCurrent.appendChild(domComment);
0x       }
          
      protected void appendDOMTree( 
          org.w3c.dom.Document domDocument, 
          org.w3c.dom.Node domCurrent,
          String text
      ) {
0x           org.w3c.dom.Text domText = domDocument.createTextNode(text);
0x           domCurrent.appendChild(domText);
0x       }
          
      protected void appendDOMTree( 
          org.w3c.dom.Document domDocument, 
          org.w3c.dom.Node domCurrent,
          Entity entity
      ) {
0x           org.w3c.dom.EntityReference domEntity = 
              domDocument.createEntityReference(entity.getName());
0x           domCurrent.appendChild(domEntity);
0x       }
          
      protected void appendDOMTree( 
          org.w3c.dom.Document domDocument, 
          org.w3c.dom.Node domCurrent,
          ProcessingInstruction pi
      ) {
0x           org.w3c.dom.ProcessingInstruction domPI =
              domDocument.createProcessingInstruction(pi.getTarget(), pi.getText());
0x           domCurrent.appendChild(domPI);
0x       }
      
      protected void writeNamespace( 
          org.w3c.dom.Element domElement, 
          Namespace namespace
      ) {
0x           String attributeName = attributeNameForNamespace(namespace);
          //domElement.setAttributeNS("", attributeName, namespace.getURI());
0x           domElement.setAttribute(attributeName, namespace.getURI());
0x       }
      
      protected String attributeNameForNamespace(Namespace namespace) {
0x           String xmlns = "xmlns";
0x           String prefix = namespace.getPrefix();
0/2 0x           if ( prefix.length() > 0 ) {
0x               return xmlns + ":" + prefix;
          }
0x           return xmlns;
      }
      
      protected org.w3c.dom.Document createDomDocument(
          Document document
      ) throws DocumentException {
0x           org.w3c.dom.Document result = null;
          
          // use the given domDocumentClass (if not null)
0/2 0x           if (domDocumentClass != null) {
              try {
0x                   result = (org.w3c.dom.Document) domDocumentClass.newInstance();
              }
              catch (Exception e) {
0x                   throw new DocumentException( 
                      "Could not instantiate an instance of DOM Document with class: " 
                      + domDocumentClass.getName(), e 
                  );
0x               }
          } else {
              // lets try JAXP first before using the hardcoded default parsers
0x               result = createDomDocumentViaJAXP();
0/2 0x               if ( result == null ) {
0x                   Class theClass = getDomDocumentClass();
                  try {
0x                       result = (org.w3c.dom.Document) theClass.newInstance();
                  }
                  catch (Exception e) {
0x                       throw new DocumentException( 
                          "Could not instantiate an instance of DOM Document with class: " 
                          + theClass.getName(), e 
                      );
0x                   }
              }
          }
          
0x           return result;
      }
      
      protected org.w3c.dom.Document createDomDocumentViaJAXP() throws DocumentException {
          try {
0x               return JAXPHelper.createDocument( false, true );
          }
          catch (Throwable e) {
0/2 0x               if ( ! loggedWarning ) {                    
0x                   loggedWarning = true;
0/2 0x                   if ( SAXHelper.isVerboseErrorReporting() ) {
                      // log all exceptions as warnings and carry
                      // on as we have a default SAX parser we can use
0x                       System.out.println( 
                          "Warning: Caught exception attempting to use JAXP to "
                           + "create a W3C DOM document" 
                      );
0x                       System.out.println( "Warning: Exception was: " + e );
0x                       e.printStackTrace();
                  }
                  else {
0x                       System.out.println( 
                          "Warning: Error occurred using JAXP to create a DOM document." 
                      );
                  }
              }
          }
0x           return null;
      }
      protected org.w3c.dom.Document createDomDocument(
          Document document, 
          org.w3c.dom.DOMImplementation domImplementation
      ) throws DocumentException {
          
0x           String namespaceURI = null;
0x           String qualifiedName = null;
0x           org.w3c.dom.DocumentType docType = null;
0x           return domImplementation.createDocument( 
              namespaceURI, qualifiedName, docType 
          );
      }
 
      protected boolean isNamespaceDeclaration( Namespace ns ) {
0/6 0x           if (ns != null && ns != Namespace.NO_NAMESPACE && ns != Namespace.XML_NAMESPACE) {
0x               String uri = ns.getURI();
0/4 0x               if ( uri != null && uri.length() > 0 ) {
0/2 0x                   if ( ! namespaceStack.contains( ns ) ) {
0x                       return true;
 
                  }
              }
          }
0x           return false;
      }
      
      protected void resetNamespaceStack() {
0x           namespaceStack.clear();
0x           namespaceStack.push( Namespace.XML_NAMESPACE );
0x       }
  }
 
 
 
 
  /*
   * 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-2004 (C) MetaStuff, Ltd. All Rights Reserved.
   *
   * $Id: DOMWriter.java,v 1.15 2004/06/28 14:19:33 maartenc Exp $
   */