Menu

assertXmlEquals fails on collection of nodes

2002-12-23
2013-03-03
  • Bj�rn Hamre

    Bj�rn Hamre - 2002-12-23

    When I have a collection of nodes (here named mat), each having several children, the assertXmlEqual fails when the sequence of the toplevel nodes (mat) are different in the control and test xml, even though the content of the two mat-nodes are equal.

    Is this a bug or unsupported feature, or must the elements in a collection have the same sequence for the collection to be considered equal?

    String control = "<eiendomer><mat><nr>1</nr></mat><mat><nr>4</nr></mat></eiendomer>";
          String test = "<eiendomer><mat><nr>4</nr></mat><mat><nr>1</nr></mat></eiendomer>";
          xmlTestCase.assertXMLEqual(control, test);

     
    • tim bacon

      tim bacon - 2002-12-27

      Yes: XMLUnit will flag child elements with repeated names as different if they are presented in a different sequence. (This is because it requires different qualified xpaths to reach the inner 'nr' nodes which are comparable: /eiendomer[1]/mat[1]/nr[1] vs. /eiendomer[1]/mat[2]/nr[1]).

      However this is not the first request to be able to have finer grained control over the strategy for determining which nodes should be compared when a difference is evaluated.

      So I have updated the source in CVS (at http://sourceforge.net/cvs/?group_id=23187\) to add an ElementQualifier interface that can be implemented as you see fit, and then supplied to the overrideElementQualifier() method of the Diff class.

      This change will likely find its way into the 1.0 release of the project... let me know if you find it useful ;-)

      Rgds,

      Tim

       
      • Sebastian

        Sebastian - 2005-04-19

        >So I have updated the source in CVS (at http://sourceforge.net/cvs/?group_id=23187\) to add an ElementQualifier interface that can be implemented as you see fit, and then supplied to the overrideElementQualifier() method of the Diff class.

        >This change will likely find its way into the 1.0 release of the project... let me know if you find it useful ;-)

        This doesn't work with version 1.0 nor with the latest CVS version. Does anyone solved this?

         
    • darzee

      darzee - 2004-11-11

      Has anyone found any solution to this problem yet? I have a similar problem and have not been able to solve this.

      I have written my own ElementQualifier class but it does not seem to have any impact (and yes, I do override it in my Diff object). The code for the qualifier is at the bottom of this message.

      The XML I am trying to compare looks like this:

      <t1>
      <t2>
        <t3>one</t3>
      </t2>
      <t2>
        <t3>two</t3>
      </t2>
      </t1>

      and

      <t1>
      <t2>
        <t3>two</t3>
      </t2>
      <t2>
        <t3>one</t3>
      </t2>
      </t1>

      and the code like this:

      String xml1 = "<t1><t2><t3>one</t3></t2><t2><t3>two</t3></t2></t1>";
      String xml2 = "<t1><t2><t3>two</t3></t2><t2><t3>one</t3></t2></t1>";
      Diff diff = new Diff(xml1,xml2);
      diff.overrideElementQualifier(new ElementNoSequenceQualifier());
      assertXMLEqual(diff, true);

      And finally here's my ElementQualifier. It is based on the ElementNameAndTextQualifier:

      public class ElementNoSequenceQualifier extends ElementNameQualifier
      {
          public boolean qualifyForComparison(Element control, Element test)
          {
              if (super.qualifyForComparison(control, test))
              {
                  boolean s = similar(extractText(control), extractText(test));

                  if (!s)
                  {
                      // Try to find element elsewhere in the xml tree
                      // Control element not present in current test element
                      Node parent = test.getParentNode();
                      if (parent != null)
                      {
                          Node nextParent = parent.getNextSibling();
                          while (nextParent != null || !s)
                          {
                              String sieblingName = nextParent.getNodeName();
                              String controlName = parent.getNodeName();
                              // Check if tag is the same as the control tag
                              if (sieblingName.equals(controlName))
                              {
                                  // Check if tag has children
                                  NodeList children = nextParent.getChildNodes();
                                  for (int i = 0, size = children.getLength(); i < size && !s; i++)
                                  {
                                      Node c = children.item(i);

                                      // Find control tag among children tags
                                      if (c.getNodeName().equals(control.getNodeName()))
                                      {
                                          // Compare text
                                          NodeList textNodes = c.getChildNodes();
                                          for (int j = 0, count = textNodes.getLength(); j < count && !s; j++)
                                          {
                                              Node t = textNodes.item(j);
                                              Text text = null;
                                              if (t.getNodeType() == Node.TEXT_NODE)
                                                  text = (Text) t;
                                              s = similar(extractText(control), text);
                                          }
                                      }
                                  }
                              }

                              nextParent = nextParent.getNextSibling();
                          }
                      }
                  }

                  return s;
              }

              return false;
          }

          protected boolean similar(Text control, Text test)
          {
              if (control == null)
                  return test == null;
              if (test == null)
                  return false;
              else
                  return control.getNodeValue().equals(test.getNodeValue());
          }

          protected Text extractText(Element fromElement)
          {
              fromElement.normalize();
              NodeList fromNodeList = fromElement.getChildNodes();

              for (int i = 0; i < fromNodeList.getLength(); i++)
              {
                  Node currentNode = fromNodeList.item(i);
                  if (currentNode.getNodeType() == Node.TEXT_NODE)
                      return (Text) currentNode;
              }

              return null;
          }
      }

       
    • Jamie Bisotti

      Jamie Bisotti - 2005-09-09

      I don't think Tim said he solved the problem.  He said he provided a way for others to solve the problem.  However, this seems VERY useful, for a general population standpoint.  Tim, is there any chance an implementation of ElementQualifier, that does solve the problem, will makes its way into CVS???

      Thanks,
         Jamie

       

Log in to post a comment.