Compare XML ignoring order of child elements

Viewed 42174

Does anybody know of a tool that will compare two XML documents. Belay that mocking… there’s more. I need something that will make sure each node in file 1 is also in file 2 regardless of order. I thought XML Spy would do it with the Ignore Order of Child Nodes option but it didn’t. The following would be considered the same:

<Node>
    <Child name="Alpha"/>
    <Child name="Beta"/>
    <Child name="Charlie"/>
</Node>

<Node>
    <Child name="Beta"/>
    <Child name="Charlie"/>
    <Child name="Alpha"/>
</Node>
13 Answers

Here is a diff solution using SWI-Prolog

:- use_module(library(xpath)).
load_trees(XmlRoot1, XmlRoot2) :-
    load_xml('./xml_source_1.xml', XmlRoot1, _),
    load_xml('./xml_source_2.xml', XmlRoot2, _).

find_differences(Reference, Root1, Root2) :-
    xpath(Root1, //'Child'(@name=Name), Node),
    not(xpath(Root2, //'Child'(@name=Name), Node)),
    writeln([Reference, Name, Node]).

diff :-
    load_trees(Root1, Root2),
    (find_differences('1', Root1, Root2) ; find_differences('2', Root2, Root1)).

Prolog will unify the Name variable to match nodes from file 1 and file 2. The unification on the Node variable does the "diff" detection.

Here's some sample output below:

% file 1 and file 2 have no differences 
?- diff.
false.

% "Alpha" was updated  in file 2
?- diff.
[1,Alpha,element(Child,[name=Alpha],[])]
[2,Alpha,element(Child,[name=Alpha,age=7],[])]
false.

With C# You could do this and afterwards compare it with any diff tool.

public void Run()
{
    LoadSortAndSave(@".. first file ..");
    LoadSortAndSave(@".. second file ..");
}

public void LoadSortAndSave(String path)
{
    var xdoc = XDocument.Load(path);
    SortXml(xdoc.Root);
    File.WriteAllText(path + ".sorted", xdoc.ToString());
}

private void SortXml(XContainer parent)
{
    var elements = parent.Elements()
        .OrderBy(e => e.Name.LocalName)
        .ToArray();

    Array.ForEach(elements, e => e.Remove());

    foreach (var element in elements)
    {
        parent.Add(element);
        SortXml(element);
    }
}

Wrote a simple java program to do so. Stored two XML's being compared in a HashMap, with key as XPath of element(including text value of element) and value as number of occurrences of that element. then compared two HashMap's for both keyset and values.

/** * creates a map of elements with text values and no nested nodes.
* Here Key of the map is XPATH of element concatenated with the text value of element, value of the element is number of occurrences of that element.
* * @param xmlContent * @return * @throws ParserConfigurationException * @throws SAXException * @throws IOException */

private static Map<String, Long> getMapOfElementsOfXML(String xmlContent)

        throws ParserConfigurationException, SAXException, IOException {

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

    dbf.setValidating(false);

    DocumentBuilder db = dbf.newDocumentBuilder();

    Document doc1 = db.parse(new ByteArrayInputStream(xmlContent.getBytes()));

    NodeList entries = doc1.getElementsByTagName("*");

    Map<String, Long> mapElements = new HashMap<>();

    for (int i = 0; i < entries.getLength(); i++) {

        Element element = (Element) entries.item(i);

        if (element.getChildNodes().getLength() == 1&&element.getTextContent()!=null) {

            final String elementWithXPathAndValue = getXPath(element.getParentNode())

                    + "/"

                    + element.getParentNode().getNodeName()

                    + "/"

                    + element.getTagName()

                    + "/"

                    + element.getTextContent();

            Long countValue = mapElements.get(elementWithXPathAndValue);

            if (countValue == null) {

                countValue = Long.valueOf(0l);

            } else {

                ++countValue;

            }

            mapElements.put(elementWithXPathAndValue, countValue);

        }

    }

    return mapElements;

}

static String getXPath(Node node) {

    Node parent = node.getParentNode();

    if (parent == null) {

        return "";

    }

    return getXPath(parent) + "/" + parent.getNodeName();

}

Complete program is here https://comparetwoxmlsignoringstanzaordering.blogspot.com/2018/12/java-program-to-compare-two-xmls.html

The simple way to do so is to use versioning tool like tortoise git.

  1. Create a github account
  2. Create a git repository in your git account
  3. Checkout that repository
  4. Add the other side of the file to be compared
  5. Push the content to the server
  6. Change the source with the remain side
  7. Compare your content as any source file
Related