cziegeler    02/04/15 07:03:20

  Added:       src/java/org/apache/cocoon/components/xpath
                        NodeListImpl.java XPathUtil.java
               src/java/org/apache/cocoon/xml/dom DOMUtil.java
  Log:
  Start of factoring out XMLUtil
  
  Revision  Changes    Path
  1.1                  
xml-cocoon2/src/java/org/apache/cocoon/components/xpath/NodeListImpl.java
  
  Index: NodeListImpl.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" 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
      [EMAIL PROTECTED]
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 and was  originally created by
   Stefano Mazzocchi  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.xpath;
  
  import org.w3c.dom.DocumentFragment;
  import org.w3c.dom.Element;
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  
  /**
   *  Implementation of the <code>NodeList</code> interface.<P>
   *
   * @author <a href="mailto:[EMAIL PROTECTED]";>Carsten Ziegeler</a>
   * @version CVS $Id: NodeListImpl.java,v 1.1 2002/04/15 14:03:20 cziegeler Exp $
  */
  public class NodeListImpl implements NodeList {
  
      private Node[] nodelist;
  
      /**
       * Construct a NodeList by copying.
       */
      public NodeListImpl(NodeList list) {
        if (list == null || list.getLength() == 0) {
          nodelist = null;
        } else {
          nodelist = new Node[list.getLength()];
          for(int i = 0; i < list.getLength(); i++) {
            nodelist[i] = list.item(i).cloneNode(true);
          }
        }
      }
  
      /**
       * Constructor
       */
      public NodeListImpl(Node[] nodes) {
          this.nodelist = nodes;
      }
  
      /**
       * Constructor
       */
      public NodeListImpl() {}
  
      /**
       * Construct a NodeList by copying.
       */
      public NodeListImpl(DocumentFragment fragment, String rootName) {
        if (fragment != null) {
          Element root = fragment.getOwnerDocument().createElementNS(null, rootName);
          Node    current;
          while (fragment.hasChildNodes() == true) {
            current = fragment.getFirstChild();
            fragment.removeChild(current);
            root.appendChild(current);
          }
          nodelist = new Node[1];
          nodelist[0] = root;
        }
      }
  
      /**
       * Add a node to list
       */
      public void addNode(Node node) {
          if (this.nodelist == null) {
              this.nodelist = new Node[1];
              this.nodelist[0] = node;
          } else {
              Node[] copy = new Node[this.nodelist.length+1];
              System.arraycopy(this.nodelist, 0, copy, 0, this.nodelist.length);
              copy[copy.length-1] = node;
              this.nodelist = copy;
          }
      }
  
      /**
       *  Returns the <code>index</code> th item in the collection. If
       * <code>index</code> is greater than or equal to the number of nodes in
       * the list, this returns <code>null</code> .
       * @param index  Index into the collection.
       * @return  The node at the <code>index</code> th position in the
       *   <code>NodeList</code> , or <code>null</code> if that is not a valid
       *   index.
       */
      public Node item(int index) {
        if (nodelist == null || index >= nodelist.length) {
          return null;
        } else {
          return nodelist[index];
        }
      }
  
      /**
       *  The number of nodes in the list. The range of valid child node indices
       * is 0 to <code>length-1</code> inclusive.
       */
      public int getLength() {
        return (nodelist == null ? 0 : nodelist.length);
      }
  
  }
  
  
  1.1                  
xml-cocoon2/src/java/org/apache/cocoon/components/xpath/XPathUtil.java
  
  Index: XPathUtil.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" 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
      [EMAIL PROTECTED]
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 and was  originally created by
   Stefano Mazzocchi  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.xpath;
  
  
  import org.apache.cocoon.ProcessingException;
  import org.w3c.dom.*;
  
  /**
   * This is a simple XPath helper class. It uses a faster approach
   * for simple XPath expressions and can create XPaths.
   * If you know that your XPath expression is simple, you should use this
   * helper instead.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]";>Carsten Ziegeler</a>
   * @version CVS $Id: XPathUtil.java,v 1.1 2002/04/15 14:03:20 cziegeler Exp $
  */
  public final class XPathUtil {
  
      /**
       * Return the <CODE>Node</CODE> from the DOM Node <CODE>rootNode</CODE>
       * using the XPath expression <CODE>path</CODE>.
       * If the node does not exist, it is created and then returned.
       * This is a very simple method for creating new nodes. If the
       * XPath contains selectors ([,,,]) or "*" it is of course not
       * possible to create the new node. So if you use such XPaths
       * the node must exist beforehand.
       * An simple exception is if the expression contains attribute
       * tests to values (e.g. [@id = 'du' and @number = 'you'],
       * the attributes with the given values are added. The attributes
       * must be separated with 'and'.
       * Another problem are namespaces: XPath requires sometimes selectors for
       * namespaces, e.g. : /*[namespace-uri()="uri" and local-name()="name"]
       * Creating such a node with a namespace is not possible right now as we use
       * a very simple XPath parser which is not able to parse all kinds of selectors
       * correctly.
       *
       * @param processor The XPathProcessor
       * @param rootNode The node to start the search.
       * @param path     XPath expression for searching the node.
       * @return         The node specified by the path.
       * @throws ProcessingException If no path is specified or the XPath engine fails.
       */
      public static Node 
getSingleNode(org.apache.avalon.excalibur.xml.xpath.XPathProcessor processor,
                                       Node rootNode,
                                       String path)
      throws ProcessingException {
          // Now we have to parse the string
          // First test:  path? rootNode?
          if (path == null) {
              throw new ProcessingException("XPath is required.");
          }
          if (rootNode == null) return rootNode;
  
          if (path.length() == 0 || path.equals("/") == true) return rootNode;
  
          // now the first "quick" test is if the node exists using the
          // full XPathAPI
          Node testNode = searchSingleNode(processor, rootNode, path);
          if (testNode != null) return testNode;
  
          if (path.startsWith("/") == true) path = path.substring(1); // remove 
leading "/"
          if (path.endsWith("/") == true) { // remove ending "/" for root node
              path = path.substring(0, path.length() - 1);
          }
  
          // now step through the nodes!
          Node parent = rootNode;
          int pos;
          int posSelector;
          do {
              pos = path.indexOf("/"); // get next separator
              posSelector = path.indexOf("[");
              if (posSelector != -1 && posSelector < pos) {
                  posSelector = path.indexOf("]");
                  pos = path.indexOf("/", posSelector);
              }
  
              String  nodeName;
              boolean isAttribute = false;
              if (pos != -1) { // found separator
                  nodeName = path.substring(0, pos); // string until "/"
                  path = path.substring(pos+1); // rest of string after "/"
              } else {
                  nodeName = path;
              }
  
              // test for attribute spec
              if (nodeName.startsWith("@") == true) {
                  isAttribute = true;
              }
  
              Node singleNode = searchSingleNode(processor, parent, nodeName);
  
              // create node if necessary
              if (singleNode == null) {
                  Node newNode;
                  // delete XPath selectors
                  int posSelect = nodeName.indexOf("[");
                  String XPathExp = null;
                  if (posSelect != -1) {
                      XPathExp = nodeName.substring(posSelect+1, nodeName.length()-1);
                      nodeName = nodeName.substring(0, posSelect);
                  }
                  if (isAttribute == true) {
                      try {
                          newNode = 
rootNode.getOwnerDocument().createAttributeNS(null, nodeName);
                      } catch (DOMException local) {
                          throw new ProcessingException("Unable to create new DOM 
node: '"+nodeName+"'.", local);
                      }
                  } else {
                      try {
                          newNode = rootNode.getOwnerDocument().createElementNS(null, 
nodeName);
                      } catch (DOMException local) {
                          throw new ProcessingException("Unable to create new DOM 
node: '"+nodeName+"'.", local);
                      }
                      if (XPathExp != null) {
                          java.util.List attrValuePairs = new java.util.ArrayList(4);
                          boolean noError = true;
  
                          String attr;
                          String value;
                          // scan for attributes
                          java.util.StringTokenizer tokenizer = new 
java.util.StringTokenizer(XPathExp, "= ");
                          while (tokenizer.hasMoreTokens() == true) {
                              attr = tokenizer.nextToken();
                              if (attr.startsWith("@") == true) {
                                  if (tokenizer.hasMoreTokens() == true) {
                                      value = tokenizer.nextToken();
                                      if (value.startsWith("'") && 
value.endsWith("'")) value = value.substring(1, value.length()-1);
                                      if (value.startsWith("\"") && 
value.endsWith("\"")) value = value.substring(1, value.length()-1);
                                      attrValuePairs.add(attr.substring(1));
                                      attrValuePairs.add(value);
                                  } else {
                                      noError = false;
                                  }
                              } else if (attr.trim().equals("and") == false) {
                                  noError = false;
                              }
                          }
                          if (noError == true) {
                              for(int l=0;l<attrValuePairs.size();l=l+2) {
                                  ((Element)newNode).setAttributeNS(null, 
(String)attrValuePairs.get(l),
                                                                  
(String)attrValuePairs.get(l+1));
                              }
                          }
                      }
                  }
                  parent.appendChild(newNode);
                  parent = newNode;
              } else {
                  parent = singleNode;
              }
          } while (pos != -1);
          return parent;
      }
  
      /**
       * Use an XPath string to select a single node. XPath namespace
       * prefixes are resolved from the context node.
       *
       * @param contextNode The node to start searching from.
       * @param str A valid XPath string.
       * @return The first node found that matches the XPath, or null.
       *
       */
      public static Node 
searchSingleNode(org.apache.avalon.excalibur.xml.xpath.XPathProcessor processor,
                                          Node contextNode,
                                          String str) {
          String[] pathComponents = buildPathArray(str);
          if (pathComponents == null) {
              return processor.selectSingleNode(contextNode, str);
          } else {
              return getFirstNodeFromPath(contextNode, pathComponents, false);
          }
      }
  
      /**
       *  Use an XPath string to select a nodelist.
       *  XPath namespace prefixes are resolved from the contextNode.
       *
       *  @param contextNode The node to start searching from.
       *  @param str A valid XPath string.
       *  @return A NodeList, should never be null.
       *
       */
      public static NodeList 
searchNodeList(org.apache.avalon.excalibur.xml.xpath.XPathProcessor processor,
                                            Node contextNode,
                                            String str) {
          String[] pathComponents = buildPathArray(str);
          if (pathComponents == null) {
              return processor.selectNodeList(contextNode, str);
          } else {
              return getNodeListFromPath(contextNode, pathComponents);
          }
      }
  
      /**
       * Build the input for the get...FromPath methods. If the XPath
       * expression cannot be handled by the methods, <code>null</code>
       * is returned.
       */
      public static String[] buildPathArray(String xpath) {
          String[] result = null;
          if (xpath != null && xpath.charAt(0) != '/') {
              // test
              int components = 1;
              int i, l;
              l = xpath.length();
              boolean found = false;
              i = 0;
              while (i < l && found == false) {
                  switch (xpath.charAt(i)) {
                      case '[' : found = true; break;
                      case '(' : found = true; break;
                      case '*' : found = true; break;
                      case '@' : found = true; break;
                      case ':' : found = true; break;
                      case '/' : components++;
                      default: i++;
                  }
              }
              if (found == false) {
                  result = new String[components];
                  if (components == 1) {
                      result[components-1] = xpath;
                  } else {
                      i = 0;
                      int start = 0;
                      components = 0;
                      while (i < l) {
                          if (xpath.charAt(i) == '/') {
                              result[components] = xpath.substring(start, i);
                              start = i+1;
                              components++;
                          }
                          i++;
                      }
                      result[components] = xpath.substring(start);
                  }
              }
          }
          return result;
      }
  
      /**
       * Use a path to select the first occurence of a node. The namespace
       * of a node is ignored!
       * @param contextNode The node starting the search.
       * @param path        The path to search the node. The
       *                    contextNode is searched for a child named path[0],
       *                    this node is searched for a child named path[1]...
       * @param create      If a child with the corresponding name is not found
       *                    and create is set, this node will be created.
      */
      public static Node getFirstNodeFromPath(Node contextNode,
                                              final String[] path,
                                              final boolean  create) {
          if (contextNode == null || path == null || path.length == 0)
              return contextNode;
          // first test if the node exists
          Node item = getFirstNodeFromPath(contextNode, path, 0);
          if (item == null && create == true) {
              int i = 0;
              NodeList childs;
              boolean found;
              int m, l;
              while (contextNode != null && i < path.length) {
                  childs = contextNode.getChildNodes();
                  found = false;
                  if (childs != null) {
                      m = 0;
                      l = childs.getLength();
                      while (found == false && m < l) {
                          item = childs.item(m);
                          if (item.getNodeType() == Document.ELEMENT_NODE
                              && item.getLocalName().equals(path[i]) == true) {
                              found = true;
                              contextNode = item;
                          }
                          m++;
                      }
                  }
                  if (found == false) {
                      Element e = contextNode.getOwnerDocument().createElementNS(null, 
path[i]);
                      contextNode.appendChild(e);
                      contextNode = e;
                  }
                  i++;
              }
              item = contextNode;
          }
          return item;
      }
  
      /**
       * Private helper method for getFirstNodeFromPath()
       */
      private static Node getFirstNodeFromPath(final Node contextNode,
                                               final String[] path,
                                               final int      startIndex) {
          int i = 0;
          NodeList childs;
          boolean found;
          int l;
          Node item = null;
  
          childs = contextNode.getChildNodes();
          found = false;
          if (childs != null) {
              i = 0;
              l = childs.getLength();
              while (found == false && i < l) {
                  item = childs.item(i);
                  if (item.getNodeType() == Document.ELEMENT_NODE
                      && item.getLocalName().equals(path[startIndex]) == true) {
                      if (startIndex == path.length-1) {
                          found = true;
                      } else {
                          item = getFirstNodeFromPath(item, path, startIndex+1);
                          if (item != null) found = true;
                      }
                  }
                  if (found == false) {
                      i++;
                  }
              }
              if (found == false) {
                  item = null;
              }
          }
          return item;
      }
  
      /**
       * Use a path to select all occurences of a node. The namespace
       * of a node is ignored!
       * @param contextNode The node starting the search.
       * @param path        The path to search the node. The
       *                    contextNode is searched for a child named path[0],
       *                    this node is searched for a child named path[1]...
       */
      public static NodeList getNodeListFromPath(Node contextNode,
                                                 String[] path) {
          if (contextNode == null) return new NodeListImpl();
          if (path == null || path.length == 0) {
              return new NodeListImpl(new Node[] {contextNode});
          }
          NodeListImpl result = new NodeListImpl();
          getNodesFromPath(result, contextNode, path, 0);
          return result;
      }
  
      /**
       * Helper method for getNodeListFromPath()
       */
      private static void getNodesFromPath(final NodeListImpl result,
                                           final Node contextNode,
                                           final String[] path,
                                           final int startIndex) {
          final NodeList childs = contextNode.getChildNodes();
          int m, l;
          Node item;
          if (startIndex == (path.length-1)) {
              if (childs != null) {
                  m = 0;
                  l = childs.getLength();
                  while (m < l) {
                      item = childs.item(m);
                      if (item.getNodeType() == Document.ELEMENT_NODE
                          && item.getLocalName().equals(path[startIndex]) == true) {
                          result.addNode(item);
                      }
                      m++;
                  }
              }
          } else {
              if (childs != null) {
                  m = 0;
                  l = childs.getLength();
                  while (m < l) {
                      item = childs.item(m);
                      if (item.getNodeType() == Document.ELEMENT_NODE
                          && item.getLocalName().equals(path[startIndex]) == true) {
                          getNodesFromPath(result, item, path, startIndex+1);
                      }
                      m++;
                  }
              }
          }
      }
  
  
  }
  
  
  
  1.1                  xml-cocoon2/src/java/org/apache/cocoon/xml/dom/DOMUtil.java
  
  Index: DOMUtil.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" 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
      [EMAIL PROTECTED]
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 and was  originally created by
   Stefano Mazzocchi  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.xml.dom;
  
  import org.apache.avalon.excalibur.source.SourceParameters;
  import org.apache.avalon.excalibur.xml.Parser;
  import org.apache.avalon.excalibur.xml.xpath.XPathProcessor;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.components.xpath.XPathUtil;
  import org.apache.cocoon.xml.IncludeXMLConsumer;
  import org.w3c.dom.*;
  import org.xml.sax.InputSource;
  import org.xml.sax.SAXException;
  import org.xml.sax.helpers.AttributesImpl;
  import java.io.*;
  
  /**
   *  This class is an utitity class for miscellaneous DOM functions, like
   *  getting and setting values of nodes.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]";>Carsten Ziegeler</a>
   * @version CVS $Id: DOMUtil.java,v 1.1 2002/04/15 14:03:20 cziegeler Exp $
  */
  public final class DOMUtil {
  
      /**
       * Get the owner of the DOM document belonging to the node.
       * This works even if the node is the document itself.
       *
       * @param node The node.
       * @return     The corresponding document.
       */
      public static Document getOwnerDocument(Node node) {
          if (node.getNodeType() == Node.DOCUMENT_NODE) {
              return (Document)node;
          } else {
              return node.getOwnerDocument();
          }
      }
  
      /**
       * Get the value of the node specified by the XPath.
       * This works similar to xsl:value-of. If the node does not exist 
<CODE>null</CODE>
       * is returned.
       *
       * @param root The node to start the search.
       * @param path XPath search expression.
       * @return     The value of the node or <CODE>null</CODE>
       */
      public static String getValueOfNode(XPathProcessor processor,
                                          Node root,
                                          String path)
      throws ProcessingException {
          if (path == null) {
              throw new ProcessingException("Not a valid XPath: " + path);
          }
          if (root == null) return null;
          if (path.startsWith("/") == true) path = path.substring(1); // remove 
leading "/"
          if (path.endsWith("/") == true) { // remove ending "/" for root node
              path = path.substring(0, path.length() - 1);
          }
  
          Node node = XPathUtil.searchSingleNode(processor, root, path);
          if (node != null) {
              return getValueOfNode(node);
          }
          return null;
      }
  
      /**
       * Get the value of the node specified by the XPath.
       * This works similar to xsl:value-of. If the node is not found
       * the <CODE>defaultValue</CODE> is returned.
       *
       * @param root The node to start the search.
       * @param path XPath search expression.
       * @param defaultValue The default value if the node does not exist.
       * @return     The value of the node or <CODE>defaultValue</CODE>
       */
      public static String getValueOfNode(XPathProcessor processor,
                                          Node root,
                                          String path,
                                          String defaultValue)
      throws ProcessingException {
          String value = getValueOfNode(processor, root, path);
          if (value == null) value = defaultValue;
  
          return value;
      }
  
      /**
       * Get the boolean value of the node specified by the XPath.
       * This works similar to xsl:value-of. If the node exists and has a value
       * this value is converted to a boolean, e.g. "true" or "false" as value
       * will result into the corresponding boolean values.
       *
       * @param root The node to start the search.
       * @param path XPath search expression.
       * @return     The boolean value of the node.
       * @throws ProcessingException If the node is not found.
       */
      public static boolean getValueOfNodeAsBoolean(XPathProcessor processor, Node 
root, String path)
      throws ProcessingException {
          String value = getValueOfNode(processor, root, path);
          if (value == null) {
              throw new ProcessingException("No such node: " + path);
          }
          return Boolean.valueOf(value).booleanValue();
      }
  
      /**
       * Get the boolean value of the node specified by the XPath.
       * This works similar to xsl:value-of. If the node exists and has a value
       * this value is converted to a boolean, e.g. "true" or "false" as value
       * will result into the corresponding boolean values.
       * If the node does not exist, the <CODE>defaultValue</CODE> is returned.
       *
       * @param root The node to start the search.
       * @param path XPath search expression.
       * @param defaultValue Default boolean value.
       * @return     The value of the node or <CODE>defaultValue</CODE>
       */
      public static boolean getValueOfNodeAsBoolean(XPathProcessor processor,Node root,
                                                String path,
                                                boolean defaultValue)
      throws ProcessingException {
          String value = getValueOfNode(processor, root, path);
          if (value == null) {
              return defaultValue;
          }
          return Boolean.valueOf(value).booleanValue();
      }
  
      /**
       * Get the value of the DOM node.
       * The value of a node is the content of the first text node.
       * If the node has no text nodes, <code>null</code> is returned.
       */
      public static String getValueOfNode(Node node) {
          if (node == null) return null;
          if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
              return node.getNodeValue();
          } else {
              String value = null;
              node.normalize();
              NodeList childs = node.getChildNodes();
              int i, l;
              i = 0;
              l = childs.getLength();
              while (i < l && value == null) {
                  if (childs.item(i).getNodeType() == Node.TEXT_NODE)
                      value = childs.item(i).getNodeValue().trim();
                  else
                      i++;
              }
              return value;
          }
      }
  
      /**
       * Get the value of the node.
       * The value of the node is the content of the first text node.
       * If the node has no text nodes the <CODE>defaultValue</CODE> is
       * returned.
       */
      public static String getValueOfNode(Node node, String defaultValue) {
          String value = getValueOfNode(node);
          if (value == null) value = defaultValue;
          return value;
      }
  
      /**
       * Set the value of the DOM node.
       * All current children of the node are removed and a new text node
       * with the value is appended.
       */
      public static void setValueOfNode(Node node, String value) {
          if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
              node.setNodeValue(value);
          } else {
              while (node.hasChildNodes() == true) {
                  node.removeChild(node.getFirstChild());
              }
              node.appendChild(node.getOwnerDocument().createTextNode(value));
          }
      }
  
      /** XML definition for a document */
      private static final String XML_DEFINITION = "<?xml version=\"1.0\" 
encoding=\"ISO-8859-1\"?>";
      private static final String XML_ROOT_DEFINITION = XML_DEFINITION + "<root>";
  
      /**
       * Get a document fragment from a <code>Reader</code>.
       * The reader must provide valid XML, but it is allowed that the XML
       * has more than one root node. This xml is parsed by the
       * specified parser instance and a DOM DocumentFragment is created.
       */
      public static DocumentFragment getDocumentFragment(Parser parser,
                                                         Reader stream)
      throws ProcessingException {
          DocumentFragment frag = null;
  
          Writer writer;
          Reader reader;
          boolean removeRoot = true;
  
          try {
              // create a writer,
              // write the root element, then the input from the
              // reader
              writer = new StringWriter();
  
              writer.write(XML_ROOT_DEFINITION);
              char[] cbuf = new char[16384];
              int    len;
              do {
                  len = stream.read(cbuf, 0, 16384);
                  if (len != -1) {
                      writer.write(cbuf, 0, len);
                  }
              } while (len != -1);
              writer.write("</root>");
  
              // now test if xml input start with <?xml
              String xml = writer.toString();
              String searchString = XML_ROOT_DEFINITION+"<?xml ";
              if (xml.startsWith(searchString) == true) {
                  // now remove the surrounding root element
                  xml = xml.substring(XML_ROOT_DEFINITION.length(), xml.length()-7);
                  removeRoot = false;
              }
  
              reader = new StringReader(xml);
  
              InputSource input = new InputSource(reader);
  
              DOMBuilder builder = new DOMBuilder();
              builder.startDocument();
              builder.startElement("", "root", "root", new AttributesImpl());
  
              IncludeXMLConsumer filter = new IncludeXMLConsumer(builder, builder);
              parser.parse(input, filter);
  
              builder.endElement("", "root", "root");
              builder.endDocument();
  
              // Create Document Fragment, remove <root>
              final Document doc = builder.getDocument();
              frag = doc.createDocumentFragment();
              final Node root = doc.getDocumentElement().getFirstChild();
              root.normalize();
              if (removeRoot == false) {
                  root.getParentNode().removeChild(root);
                  frag.appendChild(root);
              } else {
                  Node child;
                  while (root.hasChildNodes() == true) {
                      child = root.getFirstChild();
                      root.removeChild(child);
                      frag.appendChild(child);
                  }
              }
  
          } catch (SAXException sax) {
              throw new ProcessingException("SAXException: " + sax, sax);
          } catch (IOException ioe) {
              throw new ProcessingException("IOException: " + ioe, ioe);
          }
  
          return frag;
      }
  
      /**
       * Create a parameter object from xml.
       * The xml is flat and consists of elements which all have exactly one text node:
       * <parone>value_one<parone>
       * <partwo>value_two<partwo>
       * A parameter can occur more than once with different values.
       * If <CODE>source</CODE> is not specified a new paramter object is created
       * otherwise the parameters are added to source.
       */
      public static SourceParameters createParameters(Node fragment, SourceParameters 
source) {
          SourceParameters par = (source == null ? new SourceParameters() : source);
          if (fragment != null) {
              NodeList   childs = fragment.getChildNodes();
              if (childs != null) {
                  Node current;
                  for(int i = 0; i < childs.getLength(); i++) {
                      current = childs.item(i);
  
                      // only element nodes
                      if (current.getNodeType() == Node.ELEMENT_NODE) {
                          current.normalize();
                          NodeList valueChilds = current.getChildNodes();
                          String   key;
                          StringBuffer   valueBuffer;
                          String         value;
  
                          key = current.getNodeName();
                          valueBuffer = new StringBuffer();
                          for(int m = 0; m < valueChilds.getLength(); m++) {
                              current = valueChilds.item(m); // attention: current is 
reused here!
                              if (current.getNodeType() == Node.TEXT_NODE) { // only 
text nodes
                                  if (valueBuffer.length() > 0) valueBuffer.append(' 
');
                                  valueBuffer.append(current.getNodeValue());
                              }
                          }
                          value = valueBuffer.toString().trim();
                          if (key != null && value != null && value.length() > 0) {
                              par.setParameter(key, value);
                          }
                      }
                   }
               }
          }
          return par;
      }
  
      /**
       * Create a string from a DOM document fragment.
       * Only the top level text nodes are chained together to build the text.
       */
      public static String createText(DocumentFragment fragment) {
          StringBuffer value = new StringBuffer();
          if (fragment != null) {
              NodeList   childs = fragment.getChildNodes();
              if (childs != null) {
                  Node current;
  
                  for(int i = 0; i < childs.getLength(); i++) {
                      current = childs.item(i);
  
                      // only text nodes
                      if (current.getNodeType() == Node.TEXT_NODE) {
                          if (value.length() > 0) value.append(' ');
                          value.append(current.getNodeValue());
                      }
                  }
              }
          }
          return value.toString().trim();
      }
  
  
      /**
       * Compare all attributes of two elements.
       * This method returns true only if both nodes have the same number of
       * attributes and the same attributes with equal values.
       * Namespace definition nodes are ignored
       */
      public static boolean compareAttributes(Element first, Element second) {
          NamedNodeMap attr1 = first.getAttributes();
          NamedNodeMap attr2 = second.getAttributes();
          String value;
  
          if (attr1 == null && attr2 == null) return true;
          int attr1Len = (attr1 == null ? 0 : attr1.getLength());
          int attr2Len = (attr2 == null ? 0 : attr2.getLength());
          if (attr1Len > 0) {
              int l = attr1.getLength();
              for(int i=0;i<l;i++) {
                  if (attr1.item(i).getNodeName().startsWith("xmlns:") == true)
                      attr1Len--;
              }
          }
          if (attr2Len > 0) {
              int l = attr2.getLength();
              for(int i=0;i<l;i++) {
                  if (attr2.item(i).getNodeName().startsWith("xmlns:") == true)
                      attr2Len--;
              }
          }
          if (attr1Len != attr2Len) return false;
          int i, l;
          int m, l2;
          i = 0;
          l = attr1.getLength();
          l2 = attr2.getLength();
          boolean ok = true;
          // each attribute of first must be in second with the same value
          while (i < l && ok == true) {
              value = attr1.item(i).getNodeName();
              if (value.startsWith("xmlns:") == false) {
                  ok = false;
                  m = 0;
                  while (m < l2 && ok == false) {
                      if (attr2.item(m).getNodeName().equals(value) == true) {
                          // same name, same value?
                          ok = 
attr1.item(i).getNodeValue().equals(attr2.item(m).getNodeValue());
                      }
                      m++;
                  }
              }
  
              i++;
          }
          return ok;
      }
  
  
  }
  
  
  

----------------------------------------------------------------------
In case of troubles, e-mail:     [EMAIL PROTECTED]
To unsubscribe, e-mail:          [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to