Compare SimpleXml Object

I’m trying to compare two SimpleXML Objects.

One is fetched from DB and the other one from a XML API, but the result is always false, whether the XML are in fact identical or not.

What am I doing wrong?

$objDbXml   = simplexml_load_string($objReisen->xml); // XML from DB           
$objApiXml  = simplexml_load_string(getXMlFromApi()); // XML from Api
var_dump($objDbXml->Reise->Z_LEISTUNGEN == $objApiXml->Reise->Z_LEISTUNGEN);
// Result is always false

The output of var_dump($objDbXml->Reise->Z_LEISTUNGEN , $objApiXml->Reise->Z_LEISTUNGEN):

object(SimpleXMLElement) #69 (1) {
    ["TextLine"]= > array(11) {
        [0] = > string(43) "Erlebnisreise mit höchstens 13 Teilnehmern" 
        [1] = > string(39) "Durchführungsgarantie ab 4 Teilnehmern" 
        [2] = > string(127) "Linienflug mit South African Airways von Frankfurt a.M. nach Kapstadt und zurück von Port Elizabeth (von München auf Anfrage)" 
        [3] = > string(28) "Reiseminibus mit Klimaanlage" 
        [4] = > string(111) "Übernachtungen in Hotels und Lodges sowie 2 Übernachtungen in einer exklusiven Lodge im Kariega Game Reserve" 
        [5] = > string(67) "Täglich Frühstück, 2 x Mittagessen, 4 x Abendessen, 1 Weinprobe" 
        [6] = > string(123) "1 Safari im Addo-Elephant-NP; 2 Safaris im offenen Geländewagen, 1 Wandersafari und 1 Bootsfahrt im Kariega Game Reserve" 
        [7] = > string(41) "Nationalparkgebühren und Eintrittsgelder"
        [8] = > string(14) "Reiseliteratur" 
        [9] = > string(43) "Zertifikat über 100 m² Regenwald für Sie" 
        [10] = > string(42) "Deutsch sprechende Chamäleon-Reiseleitung"
    }
}

object(SimpleXMLElement) #67 (1) {
    ["TextLine"]= > array(11)
    {
        [0] = > string(43) "Erlebnisreise mit höchstens 12 Teilnehmern" 
        [1] = > string(39) "Durchführungsgarantie ab 4 Teilnehmern" 
        [2] = > string(127) "Linienflug mit South African Airways von Frankfurt a.M. nach Kapstadt und zurück von Port Elizabeth (von München auf Anfrage)" 
        [3] = > string(28) "Reiseminibus mit Klimaanlage" 
        [4] = > string(111) "Übernachtungen in Hotels und Lodges sowie 2 Übernachtungen in einer exklusiven Lodge im Kariega Game Reserve" 
        [5] = > string(67) "Täglich Frühstück, 2 x Mittagessen, 4 x Abendessen, 1 Weinprobe" 
        [6] = > string(123) "1 Safari im Addo-Elephant-NP; 2 Safaris im offenen Geländewagen, 1 Wandersafari und 1 Bootsfahrt im Kariega Game Reserve" 
        [7] = > string(41) "Nationalparkgebühren und Eintrittsgelder" 
        [8] = > string(14) "Reiseliteratur" 
        [9] = > string(43) "Zertifikat über 100 m² Regenwald für Sie" 
        [10] = > string(42) "Deutsch sprechende Chamäleon-Reiseleitung"
    }
}

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

The problem here, as so often with SimpleXML, is in the fact that a SimpleXMLElement is not a “normal” PHP object. SimpleXML is not a parser which spits out fully-formed PHP objects with properties and methods, but a “live” API linked to an internal representation of an XML document.

The manual page on Comparing Objects states that “Two object instances are equal if they have the same attributes and values, and are instances of the same class.” When you run print_r() or var_dump() over a SimpleXMLElement it appears to have properties representing the child nodes and attributes, which would be the same for two objects built from identical XML. However, the actual implementation contains only a pointer into a memory structure created when the XML was parsed, which will be different even if you parse the same string twice. Thus simply comparing two SimpleXMLElement objects with == will never return true.

The actual solution depends on what exactly you want to compare:

  • if you want to see if a particular fragment of the XML is 100% identical between the two documents, you could use ->asXML() to get an XML string for that part of the document; e.g. $objDbXml->Reise->Z_LEISTUNGEN->asXML() == $objApiXml->Reise->Z_LEISTUNGEN->asXML()
  • if there are a few specific properties which you want to compare, you may be better off selecting those out and comparing them individually, so that the test returns true even if they appear in a slightly different order, or with special characters encoded slightly differently

Solution 2

The opensource TurboCommons library contains a class called XMLUtils which contains a powerful xml comparison method called isEqualTo().

With it, you can check if two xml strings or simplexml elements are equal or not, even if their elements and attributes have different order.

https://github.com/edertone/TurboCommons

To use it, download the phar file and import it to your project.

A simple example of how it works:

use org\turbocommons\src\main\php\utils\XmlUtils;

XmlUtils::isEqualTo('<root><a/></root>', '<root><a></a></root>');

// Returns true

XmlUtils::isEqualTo('<root><a/></root>', '<raat><a/></raat>');

// Returns false

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply