Wednesday, December 18, 2013

XML Subsets

XML Subsets

Most applications today use XML for some form of data saving. In testing we also need to validate XML files, find entries in the XML via XPath and search for differences in the XML.
A lot of these abilities can be found in the lib of XMLUnit (http://xmlunit.sourceforge.net/)
This lib knows how to compare XML files, and other actions like:
·         The differences between two pieces of XML
·         The outcome of transforming a piece of XML using XSLT
·         The evaluation of an XPath expression on a piece of XML
·         The validity of a piece of XML
·         Individual nodes in a piece of XML that are exposed by DOM Traversal
One feature that I needed that it did not support is to detect if one XML is a subset of another. For example
I would like to check the following XML is a subset of the next one.
<a>
    <b>
        test b
    </b>
</a>
<a>
    <b>
        test a
    </b>
    <b>
        test b
    </b>
</a>
As you can guess a simple compare will fail since it will compare the first node of b in both XML’s and since the elements are not same it fails. What we need to do is to recursively search all nodes that have the same name and check if they are the same and not to stop on the first. This problem of course is not just on nodes but on attributes as well. If you need this functionally then you can grab the code below:

public class XmlSubsetHelper {
       static private boolean equalNotNullPointers(Object a, Object b) {
              if ((a == null && b != null) || (a != null && b == null)) {
                     return false;
              }
              return true;
       }

       static public boolean isSubset(NamedNodeMap namedNodeMapA,
                     NamedNodeMap namedNodeMapB) {
              if (!equalNotNullPointers(namedNodeMapA, namedNodeMapB)) {
                     return false;
              }
              if ((namedNodeMapA == null && namedNodeMapB == null)) {
                     return true;
              }
              for (int i = 0; i < namedNodeMapA.getLength(); i++) {
                     Node itemA = namedNodeMapA.item(i);
                     Node itemB = namedNodeMapB.getNamedItem(itemA.getNodeName());
                     if (itemB == null) {
                           return false;
                     }
                     if (!itemA.getNodeValue().equals(itemB.getNodeValue())) {
                           return false;
                     }
              }
              return true;

       }

       static public boolean isSubset(NodeList childNodesA, NodeList childNodesB) {
              if (!equalNotNullPointers(childNodesA, childNodesB)) {
                     return false;
              }
              if ((childNodesA == null && childNodesB == null)) {
                     return true;
              }
              for (int a = 0; a < childNodesA.getLength(); a++) {
                     boolean foundMatch = false;
                     Node itemA = childNodesA.item(a);
                     for (int b = 0; b < childNodesB.getLength(); b++) {
                           Node itemB = childNodesB.item(b);
                           if (isSubset(itemA, itemB)) {
                                  foundMatch = true;
                                  break;
                           }
                     }
                     if (!foundMatch) {
                           return false;
                     }
              }
              return true;
       }

       static public boolean isSubset(Node nodeA, Node nodeB) {
              if (!equalNotNullPointers(nodeA, nodeB)) {
                     return false;
              }
              if ((nodeA == null && nodeB == null)) {
                     return true;
              }
              if (!nodeA.getNodeName().equals(nodeB.getNodeName())) {
                     return false;
              }
              if (!isSubset(nodeA.getChildNodes(), nodeB.getChildNodes())) {
                     return false;
              }
              if (!isSubset(nodeA.getAttributes(), nodeB.getAttributes())) {
                     return false;
              }

              return true;
       }

       static public boolean isSubset(Document documentA, Document documentB) {
              if (!documentA.getDocumentElement().getNodeName()
                           .equals(documentB.getDocumentElement().getNodeName())) {
                     return false;
              }
              if (!isSubset(documentA.getDocumentElement(),
                           documentB.getDocumentElement())) {
                     return false;
              }
              return true;
       }

       static public Document parseXML(String xmlSource) {
              try {
                     DocumentBuilderFactory factory = DocumentBuilderFactory
                                  .newInstance();
                     DocumentBuilder builder = factory.newDocumentBuilder();
                     return builder.parse(new InputSource(new StringReader(xmlSource)));
              } catch (Exception e) {
                     throw new RuntimeException(e);
              }
       }

       static public boolean isSubset(String xmlA, String xmlB) {
              try {
                     return isSubset(parseXML(xmlA), parseXML(xmlB));
              } catch (Exception e) {
                     throw new RuntimeException(e);
              }

       }

}

No comments:

Post a Comment