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]