views:

442

answers:

2

I have an xml document with the following structure:

<?xml version="1.0" encoding="UTF-8"?>
<items>
  <item>
    <id>1</id>
    <url>www.test.com</url>
  </item>
  <item>
    <id>2</id>
    <url>www.test2.com</url>
  </item>
</items>

I would like to be able to search for a node value, such as the value of 1 for the id field. Then, once that node is found, select the parent node, which would be < item > and insert a new child within.

I know the concept of using dom document, but not sure how to do it in this instance.

+1  A: 

This should be a start:

$dom = new DOMDocument;
$dom->loadXML($input);
$ids = $dom->getElementsByTagName('id');
foreach ($ids as $id) {
  if ($id->nodeValue == '1') {
    $child = $dom->createElement('tagname');
    $child->appendChild($dom->createTextNode('some text'));
    $id->parentNode->appendChild($child);
  }
}
$xml = $dom->saveXML();

or something close to it.

cletus
This looks very promising! Let me give this a try.
Nic Hubbard
$id->nodeValue seems to return nothing.
Nic Hubbard
@Nic: I've tried the above and it works.
cletus
Got it working. Thanks!
Nic Hubbard
How would I then get a different child node of the parent? Such as a sibling node to the id node?
Nic Hubbard
@Nic: you could traverse the children of the parent of use `$node->nextSibling` see http://www.php.net/manual/en/class.domnode.php#domnode.props.nextsibling
cletus
A: 

You can do the same thing in a simpler way. Instead of looking for an <id/> node whose value is 1 then selecting its parent, you can reverse the relation and look for any node which has an <id/> child whose value is 1.

You can do that very easily in XPath, and here's how to do it in SimpleXML:

$items = simplexml_load_string(
    '<?xml version="1.0" encoding="UTF-8"?>
    <items>
      <item>
        <id>1</id>
        <url>www.test.com</url>
      </item>
      <item>
        <id>2</id>
        <url>www.test2.com</url>
      </item>
    </items>'
);

$nodes = $items->xpath('*[id = "1"]');
$nodes[0]->addChild('new', 'value');

echo $items->asXML();
Josh Davis
Tried this and I get a warning: Fatal error: Call to a member function addChild() on a non-object
Nic Hubbard
Then you don't have an `<id/>` child whose value is `1`. The example I posted works as-is. If the node you're looking for is not a child but rather any node in the document, then the XPath should be `//*[id = "1"]`
Josh Davis
Ah, got it, thanks.
Nic Hubbard