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.
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.
You could use DOMDocument.GetElementsByTagName
or you could:
Use XPath?
<?php
$xml = simplexml_load_file("test.xml");
$result = $xml->xpath("//certain");
print_r($result);
?>
Use DOM and XPath. Xpath allows you to select nodes (and values) from an XML DOM.
$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);
$result = '';
foreach ($xpath->evaluate('/people/certain') as $node) {
$result .= $dom->saveXml($node);
}
echo $result;
Demo: https://eval.in/162149
DOMDocument::saveXml() has a context argument. If provided it saves that node as XML. Much like outerXml()
. PHP is able to register your own classes for the DOM nodes, too. So it is even possible to add an outerXML()
function to element nodes.
class MyDomElement extends DOMElement {
public function outerXml() {
return $this->ownerDocument->saveXml($this);
}
}
class MyDomDocument extends DOMDocument {
public function __construct($version = '1.0', $encoding = 'utf-8') {
parent::__construct($version, $encoding);
$this->registerNodeClass('DOMElement', 'MyDomElement');
}
}
$dom = new MyDomDocument();
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);
$result = '';
foreach ($xpath->evaluate('/people/certain') as $node) {
$result .= $node->outerXml();
}
echo $result;
Demo: https://eval.in/162157
See http://www.php.net/manual/en/domdocument.getelementsbytagname.php
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;