Compare Simplexml Object

Compare SimpleXml Object

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

PHP & XML: How do I compare the text content of two XML Elements?

I imagine that $morphemeEntries is a fixed list of SimpleXMLElement objects and will not get updated with the added nodes. I suggest using the $morphemeDB object for the check. Additionally you can replace the loop with an Xpath expression.

$storySource = $entry->m;
$storyGloss = $entry->g;

$foundInDB = count(
$morphemeDB->xpath(
sprintf('.//morpheme[source="%s" and gloss="%s"]', $storySource, $storyGloss)
)
) > 0;

In DOM the same is possible with DOMXpath::evaluate():

$phraseSource = $xpathSource->evaluate('string(m)', $entry);
$phraseGloss = $xpathSource->evaluate('string(g)', $entry);

$foundInDB = $xpathTarget->evaluate(
sprintf(
'count(//morpheme[source="%s" and gloss="%s"]) > 0',
$storySource,
$storyGloss
)
);

In the DOM implementation you can nest createElement() into appendChild(), but you should add the content as text nodes (for proper escaping):

$newMorphemeEntry = $morphemeRootNode->appendChild(
$morphemeXmlDoc->createElement("morpheme")
);
$newMorphemeEntry
->appendChild($morphemeXmlDoc->createElement("source"))
->appendChild($morphemeXmlDoc->createTextNode($phraseSource));
$newMorphemeEntry
->appendChild($morphemeXmlDoc->createElement("gloss"))
->appendChild($morphemeXmlDoc->createTextNode($phraseGloss));

Successfully parsed SimpleXMLElement comparison to 'false' returning 'true'

Have a look here:
http://www.php.net/manual/en/language.types.boolean.php#language.types.boolean.casting

It says that SimpleXML objects created from empty tags evaluate to false. Maybe that's what's going on?

How to tell apart SimpleXML objects representing element and attribute?

There are no built-in properties in SimpleXMLElement which would allow you to tell these apart.

As others have suggested dom_import_simplexml can be appropriate, however, that function can change nodes on the fly sometimes, for example, if you pass in a list of childnodes or named childnodes, it will take those and turn them into the first element.

If it's an empty list, for example no attributes returned from attributes() or non-existing named childnodes, it will give a warning telling you an invalid nodetype has been given:

Warning: dom_import_simplexml(): Invalid Nodetype to import

So if you need this precise with a snappy boolean true/false, here is how it works with Simplexml:

$isElement   = $element->xpath('.') == array($element);

$isAttribute = $element[0] == $element
and $element->xpath('.') != array($element);

It works similar with attribute lists and element lists, I've just blogged about this in the morning, you need to have some specific knowledge about what to evaluate for what, so I created a cheatsheet for it:

+------------------+---------------------------------------------+
| TYPE | TEST |
+------------------+---------------------------------------------+
| Element | $element->xpath('.') == array($element) |
+------------------+---------------------------------------------+
| Attribute | $element[0] == $element |
| | and $element->xpath('.') != array($element) |
+------------------+---------------------------------------------+
| Attributes | $element->attributes() === NULL |
+------------------+---------------------------------------------+
| Elements | $element[0] != $element |
| | and $element->attributes() !== NULL |
+------------------+---------------------------------------------+
| Single | $element[0] == $element |
+------------------+---------------------------------------------+
| Empty List | $element[0] == NULL |
+------------------+---------------------------------------------+
| Document Element | $element->xpath('/*') == array($element) |
+------------------+---------------------------------------------+
  • SimpleXML Type Cheatsheet (12 Feb 2013; by hakre)

Compare an xml element with a variable php

It should be like this:

if ((string) $xml->sticker->id == $id)

Though if you have multiple sticker elements it would be:

if ((string) $xml->sticker[0]->id == $id)

PHP: Whats's the difference between the SimpleXMLElement() class and SimpleXML_load_string()?

simplexml_load_string() (as the name suggest) load xml from a string and returns an object of SimepleXMLElement. There is no difference between this and using just the usual constructor of the class.

Update:

SimpleXML::__construct() has an additional parameter (the third one) bool $data_is_url = false. If this is true the behavior is the same as simplexml_load_file() (in conjunction with the common stream wrappers). Thus both simplexml_load_*()-functions cover the same functionality as SimpleXML::__construct().

Additional the functions simplexml_load_*() has a second parameter string $class_name = "SimpleXMLElement" to specify the class of the object to get returned. Thats not a specific feature of the functions, because you can "use" something very similar with usual instanciation too

class MyXML extends SimpleXMLElement {}
$a = new MyXML($xml);
$b = simplexml_load_string($xml, 'MyXML');

A difference between the OOP- and the procedural approach is, that the functions return false on error, but the constructor throws an Exception.

Compare two xml files, update/merge and save - php simplexml

I wrote the best code for you. You can combine 2 or more xml files.

<?php

$files = array('catalog.xml', 'user.xml');
$xml = combine_xmls($files);

echo $xml->asXML();

function combine_xmls($files, $key='name'){

foreach ($files as $file){
$a = json_decode(json_encode(simplexml_load_file($file)),true);
$b[] = $a['item'];
}

$b = call_user_func_array('array_merge', $b);
foreach($b as $a) $items[$a[$key]] = $a;

$xml = new SimpleXMLElement('<?xml version="1.0" encoding="ISO-8859-1"?><catalog></catalog>');

foreach ($items as $item ){
$node = $xml->addChild('item');
foreach ($item as $key=>$val) $node->addChild($key, $val);
}

return $xml;

}

?>

Selecting a PHP SimpleXML object element that is a number

I worked around this by using json_decode then json_encode however it feels "hacky" to me so if others might suggest a better approach - have at it.

$get_timing_code = json_decode(json_encode($reply->timing->code), true);
$med_order_data['timingCode'] = $get_timing_code['0']['0']['@attributes']['value'];

Another option using a modification of @Xorifelse answer looks like this:

$med_order_data['timingCode'] = (string) $reply->timing->code->text[0]->attributes()->value;

This works as well:
$med_order_data['timingCode'] = (string) $reply->timing->code->code->text['value'];



Related Topics



Leave a reply



Submit