cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jheym...@apache.org
Subject svn commit: r330548 [70/132] - in /cocoon/whiteboard/maven2/cocoon-flat-layout: ./ cocoon-ajax-block/ cocoon-ajax-block/api/ cocoon-ajax-block/api/src/ cocoon-ajax-block/api/src/main/ cocoon-ajax-block/api/src/main/java/ cocoon-ajax-block/api/src/main/...
Date Thu, 03 Nov 2005 14:00:48 GMT
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/dom/DOMUtil.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/dom/DOMUtil.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/dom/DOMUtil.java
(added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/dom/DOMUtil.java
Thu Nov  3 05:41:06 2005
@@ -0,0 +1,1140 @@
+/*
+ * Copyright 1999-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.xml.dom;
+
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.xml.IncludeXMLConsumer;
+import org.apache.cocoon.xml.XMLUtils;
+
+import org.apache.commons.lang.BooleanUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.excalibur.source.SourceParameters;
+import org.apache.excalibur.xml.sax.SAXParser;
+import org.apache.excalibur.xml.sax.XMLizable;
+import org.apache.excalibur.xml.xpath.NodeListImpl;
+import org.apache.excalibur.xml.xpath.XPathProcessor;
+import org.apache.excalibur.xml.xpath.XPathUtil;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ *  This class is a utility class for miscellaneous DOM functions, like
+ *  getting and setting values of nodes.
+ *
+ * @author <a href="mailto:cziegeler@s-und-n.de">Carsten Ziegeler</a>
+ * @version $Id: DOMUtil.java 164876 2005-04-26 20:49:28Z vgritsenko $
+*/
+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) {
+            path = StringUtils.strip(path, "/");
+            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 BooleanUtils.toBoolean(value);
+        }
+        return defaultValue;
+    }
+
+    /**
+     * 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) {
+            if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
+                return node.getNodeValue();
+            } else {
+                node.normalize();
+                NodeList childs = node.getChildNodes();
+                int i = 0;
+                int length = childs.getLength();
+                while (i < length) {
+                    if (childs.item(i).getNodeType() == Node.TEXT_NODE) {
+                        return childs.item(i).getNodeValue().trim();
+                    } else {
+                        i++;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 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) {
+        return StringUtils.defaultString(getValueOfNode(node), defaultValue);
+    }
+
+    /**
+     * 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(SAXParser 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", XMLUtils.EMPTY_ATTRIBUTES);
+
+            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;
+    }
+
+    /**
+     * Implementation for <code>String</code> :
+     * outputs characters representing the value.
+     *
+     * @param parent The node getting the value
+     * @param text   the value
+     */
+    public static void valueOf(Node parent, String text) throws ProcessingException {
+        if (text != null) {
+            parent.appendChild(parent.getOwnerDocument().createTextNode(text));
+        }
+    }
+
+    /**
+     * Implementation for <code>XMLizable</code> :
+     * outputs the value by calling <code>v.toSax(contentHandler)</code>.
+     *
+     * @param parent The node getting the value
+     * @param v the XML fragment
+     */
+    public static void valueOf(Node parent, XMLizable v) throws ProcessingException {
+        if (v != null) {
+            DOMBuilder builder = new DOMBuilder(parent);
+            try {
+                v.toSAX(builder);
+            } catch (SAXException e) {
+                throw new ProcessingException(e);
+            }
+        }
+    }
+
+    /**
+     * Implementation for <code>org.w3c.dom.Node</code> :
+     * converts the Node to a SAX event stream.
+     *
+     * @param parent The node getting the value
+     * @param v the value
+     */
+    public static void valueOf(Node parent, Node v) throws ProcessingException {
+        if (v != null) {
+            parent.appendChild(parent.getOwnerDocument().importNode(v, true));
+        }
+    }
+
+    /**
+     * Implementation for <code>java.util.Collection</code> :
+     * outputs the value by calling {@link #valueOf(Node, Object)} on each element of the
+     * collection.
+     *
+     * @param parent The node getting the value
+     * @param v the XML fragment
+     */
+    public static void valueOf(Node parent, Collection v) throws ProcessingException {
+        if (v != null) {
+            Iterator iterator = v.iterator();
+            while (iterator.hasNext()) {
+                valueOf(parent, iterator.next());
+            }
+        }
+    }
+
+    /**
+     * Implementation for <code>java.util.Map</code> :
+     * For each entry an element is created with the childs key and value
+     * Outputs the value and the key by calling {@link #valueOf(Node, Object)}
+     * on each value and key of the Map.
+     *
+     * @param parent The node getting the value
+     * @param v      the Map
+     */
+    public static void valueOf(Node parent, Map v) throws ProcessingException {
+        if (v != null) {
+            Iterator iterator = v.keySet().iterator();
+            Node mapNode = parent.getOwnerDocument().createElementNS(null, "java.util.map");
+            parent.appendChild(mapNode);
+            for (Iterator iter = v.entrySet().iterator(); iter.hasNext();) {
+                final Map.Entry me = (Map.Entry) iter.next();
+
+                Node entryNode = mapNode.getOwnerDocument().createElementNS(null, "entry");
+                mapNode.appendChild(entryNode);
+
+                Node keyNode = entryNode.getOwnerDocument().createElementNS(null, "key");
+                entryNode.appendChild(keyNode);
+                valueOf(keyNode, me.getKey());
+
+                Node valueNode = entryNode.getOwnerDocument().createElementNS(null, "value");
+                entryNode.appendChild(valueNode);
+                valueOf(valueNode, me.getValue());
+            }
+        }
+    }
+
+    /**
+     * Implementation for <code>Object</code> depending on its class :
+     * <ul>
+     * <li>if it's an array, call {@link #valueOf(Node, Object)} on all its elements,</li>
+     * <li>if it's class has a specific {@link #valueOf(Node, Object)} implementation,
use it,</li>
+     * <li>else, output it's string representation.</li>
+     * </ul>
+     *
+     * @param parent The node getting the value
+     * @param v the value
+     */
+    public static void valueOf(Node parent, Object v) throws ProcessingException {
+        if (v == null) {
+            return;
+        }
+
+        // Array: recurse over each element
+        if (v.getClass().isArray()) {
+            Object[] elements = (Object[]) v;
+
+            for (int i = 0; i < elements.length; i++) {
+                valueOf(parent, elements[i]);
+            }
+            return;
+        }
+
+        // Check handled object types in case they were not typed in the XSP
+
+        // XMLizable
+        if (v instanceof XMLizable) {
+            valueOf(parent, (XMLizable) v);
+            return;
+        }
+
+        // Node
+        if (v instanceof Node) {
+            valueOf(parent, (Node) v);
+            return;
+        }
+
+        // Collection
+        if (v instanceof Collection) {
+            valueOf(parent, (Collection) v);
+            return;
+        }
+
+        // Map
+        if (v instanceof Map) {
+            valueOf(parent, (Map) v);
+            return;
+        }
+
+        // Give up: hope it's a string or has a meaningful string representation
+        valueOf(parent, String.valueOf(v));
+    }
+
+    /**
+     * Use an XPath string to select a single node. XPath namespace
+     * prefixes are resolved from the context node, which may not
+     * be what you want (see the next method).
+     *
+     * @param contextNode The node to start searching from.
+     * @param str A valid XPath string.
+     * @param processor The XPath processor to use
+     * @return The first node found that matches the XPath, or null.
+     *
+     * @throws TransformerException
+     */
+    public static Node getSingleNode(Node contextNode, String str,
+                                     XPathProcessor processor)
+    throws TransformerException {
+        String[] pathComponents = buildPathArray(str);
+        if (pathComponents == null) {
+            return processor.selectSingleNode(contextNode, str);
+        } else {
+            return getFirstNodeFromPath(contextNode, pathComponents, false);
+        }
+    }
+
+    /**
+     * 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
+     * test 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 rootNode  The node to start the search.
+     * @param path      XPath expression for searching the node.
+     * @param processor The XPath processor to use
+     * @return          The node specified by the path.
+     * @throws ProcessingException If no path is specified or the XPath engine fails.
+     */
+    public static Node selectSingleNode(Node rootNode, String path, XPathProcessor processor)
+    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
+        try {
+            Node testNode = getSingleNode(rootNode, path, processor);
+            if (testNode != null)
+                return testNode;
+        } catch (javax.xml.transform.TransformerException local) {
+            throw new ProcessingException(
+                "Transforming exception during selectSingleNode with path: '"
+                    + path
+                    + "'. Exception: "
+                    + local,
+                local);
+        }
+
+        // remove leading "/" oon both ends
+        path = StringUtils.strip(path, "/");
+
+        // 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;
+            try {
+                singleNode = getSingleNode(parent, nodeName, processor);
+            } catch (javax.xml.transform.TransformerException localException) {
+                throw new ProcessingException(
+                    "XPathUtil.selectSingleNode: " + localException.getMessage(),
+                    localException);
+            }
+
+            // 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 =
+                            getOwnerDocument(rootNode).createAttributeNS(
+                                null,
+                                nodeName.substring(1));
+                        ((Element) parent).setAttributeNodeNS((org.w3c.dom.Attr) newNode);
+                        parent = newNode;
+                    } catch (DOMException local) {
+                        throw new ProcessingException(
+                            "Unable to create new DOM node: '" + nodeName + "'.",
+                            local);
+                    }
+                } else {
+                    try {
+                        newNode = getOwnerDocument(rootNode).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;
+    }
+
+    /**
+     * 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.
+     * @param processor The XPath processor to use
+     * @return     The value of the node or <CODE>null</CODE>
+     */
+    public static String getValueOf(Node root, String path,
+                                    XPathProcessor processor) throws ProcessingException
{
+        if (path == null) {
+            throw new ProcessingException("Not a valid XPath: " + path);
+        }
+        if (root == null)
+            return null;
+        path = StringUtils.strip(path, "/");
+
+        try {
+            Node node = getSingleNode(root, path, processor);
+            if (node != null) {
+                return getValueOfNode(node);
+            }
+        } catch (javax.xml.transform.TransformerException localException) {
+            throw new ProcessingException(
+                "XPathUtil.selectSingleNode: " + localException.getMessage(),
+                localException);
+        }
+        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.
+     * @param processor The XPath Processor
+     * @return     The value of the node or <CODE>defaultValue</CODE>
+     */
+    public static String getValueOf(Node root, String path, String defaultValue,
+                                    XPathProcessor processor)
+    throws ProcessingException {
+        String value = getValueOf(root, path, processor);
+        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.
+     * @param processor The XPath Processor
+     * @return     The boolean value of the node.
+     * @throws ProcessingException If the node is not found.
+     */
+    public static boolean getValueAsBooleanOf(Node root, String path,
+                                              XPathProcessor processor)
+    throws ProcessingException {
+        String value = getValueOf(root, path, processor);
+        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.
+     * @param processor The XPath Processor
+     * @return     The value of the node or <CODE>defaultValue</CODE>
+     */
+    public static boolean getValueAsBooleanOf(Node root, String path, boolean defaultValue,
+                                              XPathProcessor processor)
+    throws ProcessingException {
+        String value = getValueOf(root, path, processor);
+        if (value != null) {
+            return Boolean.valueOf(value).booleanValue();
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Create a new empty DOM document.
+     */
+    public static Document createDocument() throws ProcessingException {
+        try {
+            DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance();
+            documentFactory.setNamespaceAware(true);
+            documentFactory.setValidating(false);
+            DocumentBuilder docBuilder = documentFactory.newDocumentBuilder();
+            return docBuilder.newDocument();
+        } catch (ParserConfigurationException pce) {
+            throw new ProcessingException("Creating document failed.", pce);
+        }
+    }
+
+    /**
+     *  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.
+     *  @param processor The XPath Processor
+     *  @return A NodeIterator, should never be null.
+     *
+     * @throws TransformerException
+     */
+    public static NodeList selectNodeList(Node contextNode, String str, XPathProcessor processor)
+    throws TransformerException {
+        String[] pathComponents = buildPathArray(str);
+        if (pathComponents != null) {
+            return getNodeListFromPath(contextNode, pathComponents);
+        }
+       return processor.selectNodeList(contextNode, str);
+    }
+
+    /**
+     * 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() == Node.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() == Node.ELEMENT_NODE
+                    && path[startIndex].equals(
+                        item.getLocalName() != null ? item.getLocalName() : item.getNodeName())
+                        == 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();
+        try {
+            getNodesFromPath(result, contextNode, path, 0);
+        } catch (NullPointerException npe) {
+            // this NPE is thrown because the parser is not configured
+            // to use DOM Level 2
+            throw new NullPointerException(
+                "XMLUtil.getNodeListFromPath() did catch a NullPointerException."
+                    + "This might be due to a missconfigured XML parser which does not use
DOM Level 2."
+                    + "Make sure that you use the XML parser shipped with Cocoon.");
+        }
+        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() == Node.ELEMENT_NODE) {
+                        // Work around: org.apache.xerces.dom.ElementImpl doesn't handle
getLocalName() correct
+                        if (path[startIndex]
+                            .equals(
+                                item.getLocalName() != null
+                                    ? item.getLocalName()
+                                    : item.getNodeName())
+                            == true) {
+                            result.addNode(item);
+                        }
+                    }
+                    m++;
+                }
+            }
+        } else {
+            if (childs != null) {
+                m = 0;
+                l = childs.getLength();
+                while (m < l) {
+                    item = childs.item(m);
+                    if (item.getNodeType() == Node.ELEMENT_NODE) {
+                        // Work around: org.apache.xerces.dom.ElementImpl doesn't handle
getLocalName() correct
+                        if (path[startIndex]
+                            .equals(
+                                item.getLocalName() != null
+                                    ? item.getLocalName()
+                                    : item.getNodeName())
+                            == true) {
+                            getNodesFromPath(result, item, path, startIndex + 1);
+                        }
+                    }
+                    m++;
+                }
+            }
+        }
+    }
+
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/dom/DOMUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message