[jbpm-commits] JBoss JBPM SVN: r3918 - jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/util.

do-not-reply at jboss.org do-not-reply at jboss.org
Wed Feb 18 07:05:51 EST 2009


Author: heiko.braun at jboss.com
Date: 2009-02-18 07:05:50 -0500 (Wed, 18 Feb 2009)
New Revision: 3918

Added:
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/util/DOMWriter.java
Log:
Added DOMWriter as Utility

Added: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/util/DOMWriter.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/util/DOMWriter.java	                        (rev 0)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/util/DOMWriter.java	2009-02-18 12:05:50 UTC (rev 3918)
@@ -0,0 +1,634 @@
+package org.jbpm.pvm.internal.util;
+
+/*
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 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 end-user documentation included with the redistribution, if
+ *    any, must include the following acknowlegement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowlegement may appear in the software itself,
+ *    if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache at apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Traverse a DOM tree in order to print a document that is parsed.
+ *
+ * @author Andy Clark, IBM
+ * @author Thomas.Diesler at jboss.org
+ */
+ at SuppressWarnings("unchecked")
+public class DOMWriter
+{
+  // Print writer
+  private PrintWriter out;
+  // True, if canonical output
+  private boolean canonical;
+  // True, if pretty printing should be used
+  private boolean prettyprint;
+  // True, if the XML declaration should be written
+  private boolean writeXMLDeclaration;
+  // True, if whitespace should be ignored
+  private boolean ignoreWhitespace;
+  // Explicit character set encoding
+  private String charsetName;
+  // indent for the pretty printer
+  private int prettyIndent;
+  // True, if the XML declaration has been written
+  private boolean wroteXMLDeclaration;
+  // The node that started the write
+  private Node rootNode;
+  // True if we want namespace completion
+  private boolean completeNamespaces = true;
+  // The current default namespace
+  private String currentDefaultNamespace;
+
+  public DOMWriter(Writer w)
+  {
+    this.out = new PrintWriter(w);
+  }
+
+  public DOMWriter(Writer w, String charsetName)
+  {
+    this.out = new PrintWriter(w);
+    this.charsetName = charsetName;
+    this.writeXMLDeclaration = true;
+  }
+
+  public DOMWriter(OutputStream stream)
+  {
+    try
+    {
+      this.out = new PrintWriter(new OutputStreamWriter(stream, "UTF-8"));
+    }
+    catch (UnsupportedEncodingException e)
+    {
+      // ignore, UTF-8 should be available
+    }
+  }
+
+  public DOMWriter(OutputStream stream, String charsetName)
+  {
+    try
+    {
+      this.out = new PrintWriter(new OutputStreamWriter(stream, charsetName));
+      this.charsetName = charsetName;
+      this.writeXMLDeclaration = true;
+    }
+    catch (UnsupportedEncodingException e)
+    {
+      throw new IllegalArgumentException("Unsupported encoding: " + charsetName);
+    }
+  }
+
+  /**
+   * Print a node with explicit prettyprinting.
+   * The defaults for all other DOMWriter properties apply.
+   *
+   */
+  public static String printNode(Node node, boolean prettyprint)
+  {
+    StringWriter strw = new StringWriter();
+    new DOMWriter(strw).setPrettyprint(prettyprint).print(node);
+    return strw.toString();
+  }
+
+  public boolean isCanonical()
+  {
+    return canonical;
+  }
+
+  /**
+   * Set wheter entities should appear in their canonical form.
+   * The default is false.
+   */
+  public DOMWriter setCanonical(boolean canonical)
+  {
+    this.canonical = canonical;
+    return this;
+  }
+
+  public boolean isIgnoreWhitespace()
+  {
+    return ignoreWhitespace;
+  }
+
+  /**
+   * Set whether whitespace should be ignored.
+   * The default is false.
+   */
+  public DOMWriter setIgnoreWhitespace(boolean ignoreWhitespace)
+  {
+    this.ignoreWhitespace = ignoreWhitespace;
+    return this;
+  }
+
+  /**
+   * Set wheter subelements should have their namespaces completed.
+   * Setting this to false may lead to invalid XML fragments.
+   * The default is true.
+   */
+  public DOMWriter setCompleteNamespaces(boolean complete)
+  {
+    this.completeNamespaces = complete;
+    return this;
+  }
+
+  public boolean isPrettyprint()
+  {
+    return prettyprint;
+  }
+
+  /**
+   * Set wheter element should be indented.
+   * The default is false.
+   */
+  public DOMWriter setPrettyprint(boolean prettyprint)
+  {
+    this.prettyprint = prettyprint;
+    return this;
+  }
+
+  public boolean isWriteXMLDeclaration()
+  {
+    return writeXMLDeclaration;
+  }
+
+  /**
+   * Set wheter the XML declaration should be written.
+   * The default is false.
+   */
+  public DOMWriter setWriteXMLDeclaration(boolean flag)
+  {
+    this.writeXMLDeclaration = flag;
+    return this;
+  }
+
+  public void print(Node node)
+  {
+    if (prettyprint && ignoreWhitespace)
+      throw new IllegalStateException("Cannot pretty print and ignore whitespace");
+
+    rootNode = node;
+    printInternal(node, false);
+  }
+
+  private void printInternal(Node node, boolean indentEndMarker)
+  {
+    // is there anything to do?
+    if (node == null)
+    {
+      return;
+    }
+
+    // JBAS-2117 - Don't skip the DOCUMENT_NODE
+    // if (node instanceof Document) node = ((Document)node).getDocumentElement();
+
+    if (wroteXMLDeclaration == false && writeXMLDeclaration == true && canonical == false)
+    {
+      out.print("<?xml version='1.0'");
+      if (charsetName != null)
+        out.print(" encoding='" + charsetName + "'");
+
+      out.print("?>");
+      if (prettyprint)
+        out.println();
+
+      wroteXMLDeclaration = true;
+    }
+
+    int type = node.getNodeType();
+    boolean hasChildNodes = node.getChildNodes().getLength() > 0;
+
+    String nodeName = node.getNodeName();
+    switch (type)
+    {
+      // print document
+      case Node.DOCUMENT_NODE:
+      {
+        NodeList children = node.getChildNodes();
+        for (int iChild = 0; iChild < children.getLength(); iChild++)
+        {
+          printInternal(children.item(iChild), false);
+        }
+        out.flush();
+        break;
+      }
+
+      // print element with attributes
+      case Node.ELEMENT_NODE:
+      {
+        Element element = (Element)node;
+        if (prettyprint)
+        {
+          for (int i = 0; i < prettyIndent; i++)
+          {
+            out.print(' ');
+          }
+          prettyIndent++;
+        }
+
+        out.print('<');
+        out.print(nodeName);
+
+        Map nsMap = new HashMap();
+        String elPrefix = node.getPrefix();
+        String elNamespaceURI = node.getNamespaceURI();
+        if (elPrefix != null)
+        {
+          String nsURI = getNamespaceURI(elPrefix, element, rootNode);
+          nsMap.put(elPrefix, nsURI);
+        }
+
+        Attr attrs[] = sortAttributes(node.getAttributes());
+        for (int i = 0; i < attrs.length; i++)
+        {
+          Attr attr = attrs[i];
+          String atPrefix = attr.getPrefix();
+          String atName = attr.getNodeName();
+          String atValue = normalize(attr.getNodeValue(), canonical);
+
+          if (atName.equals("xmlns"))
+            currentDefaultNamespace = atValue;
+
+          if (atPrefix != null && !atPrefix.equals("xmlns") && !atPrefix.equals("xml"))
+          {
+            String nsURI = getNamespaceURI(atPrefix, element, rootNode);
+            nsMap.put(atPrefix, nsURI);
+            // xsi:type='ns1:SubType', xsi:type='xsd:string'
+            if (atName.equals(atPrefix + ":type") && atValue.indexOf(":") > 0)
+            {
+              // xsi defined on the envelope
+              if (nsURI == null)
+                nsURI = getNamespaceURI(atPrefix, element, null);
+
+              if ("http://www.w3.org/2001/XMLSchema-instance".equals(nsURI))
+              {
+                String typePrefix = atValue.substring(0, atValue.indexOf(":"));
+                String typeURI = getNamespaceURI(typePrefix, element, rootNode);
+                nsMap.put(typePrefix, typeURI);
+              }
+            }
+          }
+
+          out.print(" " + atName + "='" + atValue + "'");
+        }
+
+        // Add namespace declaration for prefixes
+        // that are defined further up the tree
+        if (completeNamespaces)
+        {
+          Iterator itPrefix = nsMap.keySet().iterator();
+          while (itPrefix.hasNext())
+          {
+            String prefix = (String)itPrefix.next();
+            String nsURI = (String)nsMap.get(prefix);
+            if (nsURI == null)
+            {
+              nsURI = getNamespaceURI(prefix, element, null);
+              out.print(" xmlns:" + prefix + "='" + nsURI + "'");
+            }
+          }
+        }
+
+        // The SAX ContentHandler will by default not add the namespace declaration
+        // <Hello xmlns='http://somens'>World</Hello>
+        if (elPrefix == null && elNamespaceURI != null)
+        {
+          String defaultNamespace = element.getAttribute("xmlns");
+          if (defaultNamespace.length() == 0 && !elNamespaceURI.equals(currentDefaultNamespace))
+          {
+            out.print(" xmlns='" + elNamespaceURI + "'");
+            currentDefaultNamespace = elNamespaceURI;
+          }
+        }
+
+        if (hasChildNodes)
+        {
+          out.print('>');
+        }
+
+        // Find out if the end marker is indented
+        indentEndMarker = isEndMarkerIndented(node);
+
+        if (indentEndMarker)
+        {
+          out.print('\n');
+        }
+
+        NodeList childNodes = node.getChildNodes();
+        int len = childNodes.getLength();
+        for (int i = 0; i < len; i++)
+        {
+          Node childNode = childNodes.item(i);
+          printInternal(childNode, false);
+        }
+        break;
+      }
+
+      // handle entity reference nodes
+      case Node.ENTITY_REFERENCE_NODE:
+      {
+        if (canonical)
+        {
+          NodeList children = node.getChildNodes();
+          if (children != null)
+          {
+            int len = children.getLength();
+            for (int i = 0; i < len; i++)
+            {
+              printInternal(children.item(i), false);
+            }
+          }
+        }
+        else
+        {
+          out.print('&');
+          out.print(nodeName);
+          out.print(';');
+        }
+        break;
+      }
+
+      // print cdata sections
+      case Node.CDATA_SECTION_NODE:
+      {
+        if (canonical)
+        {
+          out.print(normalize(node.getNodeValue(), canonical));
+        }
+        else
+        {
+          out.print("<![CDATA[");
+          out.print(node.getNodeValue());
+          out.print("]]>");
+        }
+        break;
+      }
+
+      // print text
+      case Node.TEXT_NODE:
+      {
+        String text = normalize(node.getNodeValue(), canonical);
+        if (text.trim().length() > 0)
+        {
+          out.print(text);
+        }
+        else if (prettyprint == false && ignoreWhitespace == false)
+        {
+          out.print(text);
+        }
+        break;
+      }
+
+      // print processing instruction
+      case Node.PROCESSING_INSTRUCTION_NODE:
+      {
+        out.print("<?");
+        out.print(nodeName);
+        String data = node.getNodeValue();
+        if (data != null && data.length() > 0)
+        {
+          out.print(' ');
+          out.print(data);
+        }
+        out.print("?>");
+        break;
+      }
+
+      // print comment
+      case Node.COMMENT_NODE:
+      {
+        for (int i = 0; i < prettyIndent; i++)
+        {
+          out.print(' ');
+        }
+
+        out.print("<!--");
+        String data = node.getNodeValue();
+        if (data != null)
+        {
+          out.print(data);
+        }
+        out.print("-->");
+
+        if (prettyprint)
+        {
+          out.print('\n');
+        }
+
+        break;
+      }
+    }
+
+    if (type == Node.ELEMENT_NODE)
+    {
+      if (prettyprint)
+        prettyIndent--;
+
+      if (hasChildNodes == false)
+      {
+        out.print("/>");
+      }
+      else
+      {
+        if (indentEndMarker)
+        {
+          for (int i = 0; i < prettyIndent; i++)
+          {
+            out.print(' ');
+          }
+        }
+
+        out.print("</");
+        out.print(nodeName);
+        out.print('>');
+      }
+
+      if (prettyIndent > 0)
+      {
+        out.print('\n');
+      }
+    }
+    out.flush();
+  }
+
+  private String getNamespaceURI(String prefix, Element element, Node stopNode)
+  {
+    Node parent = element.getParentNode();
+    String nsURI = element.getAttribute("xmlns:" + prefix);
+    if (nsURI.length() == 0 && element != stopNode && parent instanceof Element)
+      return getNamespaceURI(prefix, (Element)parent, stopNode);
+
+    return (nsURI.length() > 0 ? nsURI : null);
+  }
+
+  private boolean isEndMarkerIndented(Node node)
+  {
+    if (prettyprint)
+    {
+      NodeList childNodes = node.getChildNodes();
+      int len = childNodes.getLength();
+      for (int i = 0; i < len; i++)
+      {
+        Node children = childNodes.item(i);
+        if (children.getNodeType() == Node.ELEMENT_NODE)
+        {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  /** Returns a sorted list of attributes. */
+  private Attr[] sortAttributes(NamedNodeMap attrs)
+  {
+
+    int len = (attrs != null) ? attrs.getLength() : 0;
+    Attr array[] = new Attr[len];
+    for (int i = 0; i < len; i++)
+    {
+      array[i] = (Attr)attrs.item(i);
+    }
+    for (int i = 0; i < len - 1; i++)
+    {
+      String name = array[i].getNodeName();
+      int index = i;
+      for (int j = i + 1; j < len; j++)
+      {
+        String curName = array[j].getNodeName();
+        if (curName.compareTo(name) < 0)
+        {
+          name = curName;
+          index = j;
+        }
+      }
+      if (index != i)
+      {
+        Attr temp = array[i];
+        array[i] = array[index];
+        array[index] = temp;
+      }
+    }
+    return (array);
+  }
+
+  /** Normalizes the given string. */
+  public static String normalize(String s, boolean canonical)
+  {
+    StringBuffer str = new StringBuffer();
+
+    int len = (s != null) ? s.length() : 0;
+    for (int i = 0; i < len; i++)
+    {
+      char ch = s.charAt(i);
+      switch (ch)
+      {
+        case '<':
+        {
+          str.append("&lt;");
+          break;
+        }
+        case '>':
+        {
+          str.append("&gt;");
+          break;
+        }
+        case '&':
+        {
+          str.append("&amp;");
+          break;
+        }
+        case '"':
+        {
+          str.append("&quot;");
+          break;
+        }
+        case '\'':
+        {
+          str.append("&apos;");
+          break;
+        }
+        case '\r':
+        case '\n':
+        {
+          if (canonical)
+          {
+            str.append("&#");
+            str.append(Integer.toString(ch));
+            str.append(';');
+            break;
+          }
+          // else, default append char
+        }
+        default:
+        {
+          str.append(ch);
+        }
+      }
+    }
+    return (str.toString());
+  }
+}
\ No newline at end of file




More information about the jbpm-commits mailing list