Author: mukulg Date: Fri Jan 19 14:19:44 2024 New Revision: 1915327 URL: http://svn.apache.org/viewvc?rev=1915327&view=rev Log: implementing for XML dom documents, method 'isEqualNodeWithQName' similar to 'isEqualNode' to compare two XML elements, to support use cases like use of XPath 3.1 function fn:deep-equal.
Added: xerces/java/trunk/src/org/apache/xerces/dom/NodeEqualityWithQname.java (with props) Modified: xerces/java/trunk/src/org/apache/xerces/dom/ElementImpl.java xerces/java/trunk/src/org/apache/xerces/dom/NodeImpl.java xerces/java/trunk/src/org/apache/xerces/dom/ParentNode.java Modified: xerces/java/trunk/src/org/apache/xerces/dom/ElementImpl.java URL: http://svn.apache.org/viewvc/xerces/java/trunk/src/org/apache/xerces/dom/ElementImpl.java?rev=1915327&r1=1915326&r2=1915327&view=diff ============================================================================== --- xerces/java/trunk/src/org/apache/xerces/dom/ElementImpl.java (original) +++ xerces/java/trunk/src/org/apache/xerces/dom/ElementImpl.java Fri Jan 19 14:19:44 2024 @@ -17,6 +17,8 @@ package org.apache.xerces.dom; +import javax.xml.XMLConstants; + import org.apache.xerces.util.URI; import org.w3c.dom.Attr; import org.w3c.dom.DOMException; @@ -58,7 +60,7 @@ import org.w3c.dom.TypeInfo; */ public class ElementImpl extends ParentNode - implements Element, ElementTraversal, TypeInfo { + implements Element, ElementTraversal, TypeInfo, NodeEqualityWithQname { // // Constants @@ -934,6 +936,93 @@ public class ElementImpl } return true; } + + /** + * This method implementation is added, to support use + * cases like use of XPath 3.1 function fn:deep-equal. + */ + public boolean isEqualNodeWithQName(Node arg) { + if (!super.isEqualNodeWithQName(arg)) { + return false; + } + + boolean hasAttrs = hasAttributes(); + if (hasAttrs != ((Element) arg).hasAttributes()) { + return false; + } + + if (hasAttrs) { + NamedNodeMap map1 = getAttributes(); + NamedNodeMap map2 = ((Element) arg).getAttributes(); + + int len = map1.getLength(); + if (len != map2.getLength()) { + return false; + } + + boolean isNsDeclEqual = false; + + for (int i = 0; i < len; i++) { + Node n1 = map1.item(i); + if (n1.getLocalName() == null) { // DOM Level 1 Node + Node n2 = map2.getNamedItem(n1.getNodeName()); + if (n2 == null || !((NodeImpl) n1).isEqualNode(n2)) { + return false; + } + } + else { + String nodeName1 = n1.getNodeName(); + + if ((XMLConstants.XMLNS_ATTRIBUTE.equals(nodeName1) || + nodeName1.startsWith(XMLConstants.XMLNS_ATTRIBUTE + ":")) && + XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(n1.getNamespaceURI())) { + // This is an XML namespace declaration within the first element. + // We check whether, there's a logically equal XML namespace + // declaration present within the second element. + + // For two XML namespace declarations to be logically equal, + // the only requirement is to have their namespace uri's + // as equal. + + // Few examples of logically equal XML namespace declarations + // are following: + // (xmlns="http://a", xmlns="http://a"), + // (xmlns="http://a", xmlns:a1="http://a"), + // (xmlns:a1="http://a", xmlns="http://a"), + // (xmlns:a1="http://a", xmlns:b1="http://a") + + String nsDeclUri = n1.getNodeValue(); + int len2 = map2.getLength(); + for (int idx = 0; idx < len2; idx++) { + Node attrNode2 = map2.item(idx); + String nodeName2 = attrNode2.getNodeName(); + String nsDeclUri2 = attrNode2.getNodeValue(); + String nsUri2 = attrNode2.getNamespaceURI(); + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(nsUri2) && + (XMLConstants.XMLNS_ATTRIBUTE.equals(nodeName2) || + nodeName2.startsWith(XMLConstants.XMLNS_ATTRIBUTE + ":")) && + nsDeclUri.equals(nsDeclUri2)) { + isNsDeclEqual = true; + break; + } + } + + if (isNsDeclEqual) { + continue; + } + } + + Node n2 = map2.getNamedItemNS(n1.getNamespaceURI(), + n1.getLocalName()); + if (n2 == null || !((NodeImpl) n1).isEqualNodeWithQName(n2)) { + return false; + } + } + } + } + + return true; + } /** * DOM Level 3: register the given attribute node as an ID attribute Added: xerces/java/trunk/src/org/apache/xerces/dom/NodeEqualityWithQname.java URL: http://svn.apache.org/viewvc/xerces/java/trunk/src/org/apache/xerces/dom/NodeEqualityWithQname.java?rev=1915327&view=auto ============================================================================== --- xerces/java/trunk/src/org/apache/xerces/dom/NodeEqualityWithQname.java (added) +++ xerces/java/trunk/src/org/apache/xerces/dom/NodeEqualityWithQname.java Fri Jan 19 14:19:44 2024 @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.xerces.dom; + +import org.w3c.dom.Node; + +/** + * This interface provides support for checking equality + * of two XML element nodes, where considering XML element + * names by their QName values, to support use cases like + * XPath 3.1 function fn:deep-equal. + * + * @xerces.internal + * + * @author Mukul Gandhi <muk...@apache.org> + * + * @version $Id$ + */ +public interface NodeEqualityWithQname { + + public boolean isEqualNodeWithQName(Node arg); + +} Propchange: xerces/java/trunk/src/org/apache/xerces/dom/NodeEqualityWithQname.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: xerces/java/trunk/src/org/apache/xerces/dom/NodeEqualityWithQname.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Modified: xerces/java/trunk/src/org/apache/xerces/dom/NodeImpl.java URL: http://svn.apache.org/viewvc/xerces/java/trunk/src/org/apache/xerces/dom/NodeImpl.java?rev=1915327&r1=1915326&r2=1915327&view=diff ============================================================================== --- xerces/java/trunk/src/org/apache/xerces/dom/NodeImpl.java (original) +++ xerces/java/trunk/src/org/apache/xerces/dom/NodeImpl.java Fri Jan 19 14:19:44 2024 @@ -80,7 +80,7 @@ import org.w3c.dom.events.EventTarget; * @since PR-DOM-Level-1-19980818. */ public abstract class NodeImpl - implements Node, NodeList, EventTarget, Cloneable, Serializable{ + implements Node, NodeList, EventTarget, Cloneable, NodeEqualityWithQname, Serializable{ // // Constants @@ -1752,9 +1752,88 @@ public abstract class NodeImpl return false; } - return true; } + + /** + * Tests whether two nodes are equal. + * + * This method implementation is added, to support use + * cases like use of XPath 3.1 function fn:deep-equal. + * + * <br>This method tests for equality of nodes, not sameness (i.e., + * whether the two nodes are references to the same object) which can be + * tested with <code>Node.isSameNode</code>. All nodes that are the same + * will also be equal, though the reverse may not be true. + * <br>Two nodes are equal if and only if the following conditions are + * satisfied: The two nodes are of the same type. The following string + * attributes are equal: <code>localName</code>, <code>namespaceURI</code>, + * <code>nodeValue</code>, <code>baseURI</code>. This is: they are both + * <code>null</code>, or they have the same length and are character + * for character identical. + * The <code>attributes</code> <code>NamedNodeMaps</code> are equal. + * This is: they are both <code>null</code>, or they have the same + * length and for each node that exists in one map there is a node that + * exists in the other map and is equal, although not necessarily at the + * same index. The <code>childNodes</code> <code>NodeLists</code> are + * equal. This is: they are both <code>null</code>, or they have the + * same length and contain equal nodes at the same index. This is true + * for <code>Attr</code> nodes as for any other type of node. Note that + * normalization can affect equality; to avoid this, nodes should be + * normalized before being compared. + * <br>For two <code>DocumentType</code> nodes to be equal, the following + * conditions must also be satisfied: The following string attributes + * are equal: <code>publicId</code>, <code>systemId</code>, + * <code>internalSubset</code>. The <code>entities</code> + * <code>NamedNodeMaps</code> are equal. The <code>notations</code> + * <code>NamedNodeMaps</code> are equal. + * <br>On the other hand, the following do not affect equality: the + * <code>ownerDocument</code> attribute, the <code>specified</code> + * attribute for <code>Attr</code> nodes, the + * <code>isWhitespaceInElementContent</code> attribute for + * <code>Text</code> nodes, as well as any user data or event listeners + * registered on the nodes. + * @param arg The node to compare equality with. + * @return If the nodes, and possibly subtrees are equal, + * <code>true</code> otherwise <code>false</code>. + */ + public boolean isEqualNodeWithQName(Node arg) { + if (arg == this) { + return true; + } + if (arg.getNodeType() != getNodeType()) { + return false; + } + + if (getLocalName() == null) { + if (arg.getLocalName() != null) { + return false; + } + } + else if (!getLocalName().equals(arg.getLocalName())) { + return false; + } + + if (getNamespaceURI() == null) { + if (arg.getNamespaceURI() != null) { + return false; + } + } + else if (!getNamespaceURI().equals(arg.getNamespaceURI())) { + return false; + } + + if (getNodeValue() == null) { + if (arg.getNodeValue() != null) { + return false; + } + } + else if (!getNodeValue().equals(arg.getNodeValue())) { + return false; + } + + return true; + } /** * @since DOM Level 3 Modified: xerces/java/trunk/src/org/apache/xerces/dom/ParentNode.java URL: http://svn.apache.org/viewvc/xerces/java/trunk/src/org/apache/xerces/dom/ParentNode.java?rev=1915327&r1=1915326&r2=1915327&view=diff ============================================================================== --- xerces/java/trunk/src/org/apache/xerces/dom/ParentNode.java (original) +++ xerces/java/trunk/src/org/apache/xerces/dom/ParentNode.java Fri Jan 19 14:19:44 2024 @@ -876,6 +876,43 @@ public abstract class ParentNode } return true; } + + /** + * This method implementation is added, to support use + * cases like use of XPath 3.1 function fn:deep-equal. + */ + public boolean isEqualNodeWithQName(Node arg) { + if (!super.isEqualNodeWithQName(arg)) { + return false; + } + + // there are many ways to do this test, and there isn't any way + // better than another. Performance may vary greatly depending on + // the implementations involved. This one should work fine for us. + Node child1 = getFirstChild(); + Node child2 = arg.getFirstChild(); + + while (child1 != null && child2 != null) { + if ((child1 instanceof ElementImpl) && + (child2 instanceof ElementImpl)) { + if (!((ElementImpl)child1).isEqualNodeWithQName((ElementImpl) + child2)) { + return false; + } + } + else if (!child1.isEqualNode(child2)) { + return false; + } + child1 = child1.getNextSibling(); + child2 = child2.getNextSibling(); + } + + if (child1 != child2) { + return false; + } + + return true; + } // // Public methods --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@xerces.apache.org For additional commands, e-mail: commits-h...@xerces.apache.org