tags:

views:

196

answers:

4

Using PHP, how do I get an entire subset of nodes from an XML document? I can retrieve something like:

<?xml version="1.0" encoding="utf-8"?>
<people>
  <certain>
    <name>Jane Doe</name>
    <age>21</age>
  </certain>
  <certain>
  <certain>
    <name>John Smith</name>
    <age>34</age>
  </certain>
</people>

But what if I only want to return the child nodes of like this?

  <certain>
    <name>Jane Doe</name>
    <age>21</age>
  </certain>
  <certain>
  <certain>
    <name>John Smith</name>
    <age>34</age>
  </certain>

EDIT: I'm trying to get a subset of XML and pass that directly, not an object like simplexml would give me. I am basically trying to get PHP to do what .NET's OuterXml does... return literally the above subset of XML as is... no interpreting or converting or creating a new XML file or anything... just extract those nodes in situ and pass them on. Am I going to have to get the XML file, parse out what I need and then rebuild it as a new XML file? If so then I need to get rid of the <?xml version="1.0" encoding="utf-8"?> bit... ugh.

+2  A: 

You could use DOMDocument.GetElementsByTagName or you could:

Use XPath?

<?php
$xml = simplexml_load_file("test.xml");

$result = $xml->xpath("//certain");

print_r($result);
?>
Daniel May
This gives me an object. I am trying to get a subset of the XML to pass directly to the function. It looks like I might have to read the XML, parse it, then recreate the XML! Ugh. I hope there is an easier way. basically I want to extract <certain><name>blah</name><age>2</age></certain> and return precisely that, not an object or a new XML document... just that bit. Like OuterXml would do in .NET
rg88
+2  A: 

The answer would be to use XPath.

$people = simplexml_load_string(
    '<?xml version="1.0" encoding="utf-8"?>
    <people>
      <certain>
        <name>Jane Doe</name>
        <age>21</age>
      </certain>
      <certain>
        <name>John Smith</name>
        <age>34</age>
      </certain>
    </people>'
);

// get all <certain/> nodes
$people->xpath('//certain');

// get all <certain/> nodes whose <name/> is "John Smith"
print_r($people->xpath('//certain[name = "John Smith"]'));

// get all <certain/> nodes whose <age/> child's value is greater than 21
print_r($people->xpath('//certain[age > 21]'));


Take 2

So apparently you want to copy some nodes from a document into another document? SimpleXML doesn't support that. DOM has methods for that but they're kind of annoying to use. Which one are you using? Here's what I use: SimpleDOM. In fact, it's really SimpleXML augmented with DOM's methods.

include 'SimpleDOM.php';
$results = simpledom_load_string('<results/>');

foreach ($people->xpath('//certain') as $certain)
{
    $results->appendChild($certain);
}

That routine finds all <certain/> node via XPath, then appends them to the new document.

Josh Davis
Josh, thanks for the response. I edited the question to clarify. If you can take a look amd see if that helps explain what I'm trying to do I'd appreciate it.
rg88
SimpleDOM looks interesting but I cannot add it to the mix on this project. I'll look into using DOM to do the whole thing (and if you have any tips on doing it that way or can point me in the right direction that would be great).
rg88
+1  A: 

The answer turned out to be a combination of the xpath suggestion and outputting with asXML().

Using the example given by Josh Davis:

$people = simplexml_load_string(
      <?xml version="1.0" encoding="utf-8"?>
        <people>
          <certain>
            <name>Jane Doe</name>
            <age>21</age>
          </certain>
          <certain>
            <name>John Smith</name>
            <age>34</age>
          </certain>
        </people>'
    );

    // get all <certain/> nodes
    $nodes = $people->xpath('/people/certain');

    foreach ( $nodes as $node ) {
      $result .= $node->asXML()."\n";
    }
    echo $result;
rg88