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

Reply via email to