Question

I have a series of arbitrary XML Documents that I need to parse and perform some string manipulation on each element within the document.

For example:

<sample>
  <example>
    <name>David</name>
    <age>21</age>
  </example>
</sample>

For the nodes name and age I might want to run it through a function such as strtoupper to change the case.

I am struggling to do this in a generic way. I have been trying to use RecursiveIteratorIterator with SimpleXMLIterator to achieve this but I am unable to get the parent key to update the xml document:

$iterator = new RecursiveIteratorIterator(new SimpleXMLIterator($xml->asXML()));
foreach ($iterator as $k=> $v) {
    $iterator->$k = strtoupper($v);
}

This fails because $k in this example is 'name' so it's trying to do:

$xml->name = strtoupper($value);

When it needs to be

$xml->example->name = strtoupper($value);

As the schema of the documents change I want to use something generic to process them all but I don't know how to get the key.

Is this possible with Spl iterators and simplexml?

Was it helpful?

Solution

You are most likely looking for something that I worded SimpleXML-Self-Reference once. It does work here, too.

And yes, Simplexml has support for SPL and RecursiveIteratorIterator.

So first of all, you can directly make $xml work with tree-traversal by opening the original XML that way:

$buffer = <<<BUFFER
<sample>
  <example>
    <name>David</name>
    <age>21</age>
  </example>
</sample>
BUFFER;

$xml = simplexml_load_string($buffer, 'SimpleXMLIterator');
//                                     #################

That allows you to do all the standard modifications (as SimpleXMLIterator is as well a SimpleXMLElement) but also the recursive tree-traversal to modify each leaf-node:

$iterator = new RecursiveIteratorIterator($xml);
foreach ($iterator as $node) {
    $node[0] = strtoupper($node);
    //   ###
}

This exemplary recursive iteration over all leaf-nodes shows how to set the self-reference, the key here is to assign to $node[0] as outlined in the above link.

So all left is to output:

$xml->asXML('php://output');

Which then simply gives:

<?xml version="1.0"?>
<sample>
  <example>
    <name>DAVID</name>
    <age>21</age>
  </example>
</sample>

And that's the whole example and it should also answer your question.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top