Search code examples
phpxmldomdocument

In PHP, how to saveXML with the attributes sorted?


If I have a DOMDocument and I would like to parse it into a string, how do I ensure that the attributes will be sorted in some deterministic/normalized order (lexicographically based on the attribute name would be nice)?

For example how can I make this print equal instead of notequal?

 $dom = new DOMDocument();
 $dom->loadXML('<tag a="a" b="b"/>');
 
 $dom2 = new DOMDocument();
 $dom2->loadXML('<tag b="b" a="a"/>');

 echo $dom->saveXML() === $dom2->saveXML() ? "equal" : "notequal";

According to the documentation, saveXML only supported option is LIBXML_NOEMPTYTAG.


Solution

  • DOMNode::C14N() canonicalizes nodes to a string.

    $expected = new DOMDocument();
    $expected->loadXML('<tag a="a" b="b"/>');
    
    $actual = new DOMDocument();
    $actual->loadXML('<tag b="b" a="a"/>');
    
    echo $expected->C14N() === $actual->C14N() ? "equal" : "notequal";
    

    Output:

    equal
    

    If you're write unit tests - PHPUnit has specific assertions for XML.

    • assertXmlFileEqualsXmlFile()
    • assertXmlStringEqualsXmlFile()
    • assertXmlStringEqualsXmlString()