I am trying to query an XML file using XPath. But as return I get nothing. I think I formatted the query false.
XML
<subject id="Tom">
<relation unit="ITSupport" role="ITSupporter" />
</subject>
PHP
$xpath = new DOMXpath($doc);
$role = 'ITSupporter';
$elements = $xpath-> query("//subject/@id[../relation/@role='".$role."']");
foreach ($elements as $element) {
$name = $element -> nodeValue;
$arr[$i] = $name;
$i = $i + 1;
}
How can I get the id TOM? I want to save it to for example $var
Building up the Xpath expression:
subject
element//subject
relation
//subject[relation]
role
attribute with the given text//subject[relation/@role="ITSupporter"]
@id
attribute of subject
//subject[relation/@role="ITSupporter"]/@id
Additionally the source could be cleaned up. PHP arrays can use the $array[]
syntax to push new elements into them.
Put together:
$xml = <<<'XML'
<subject id="Tom">
<relation unit="ITSupport" role="ITSupporter" />
</subject>
XML;
$role = 'ITSupporter';
$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);
$ids = [];
foreach ($xpath->evaluate("//subject[relation/@role='".$role."']/@id") as $idAttribute) {
$ids[] = $idAttribute->value;
}
var_dump($ids);
Output:
array(1) {
[0]=>
string(3) "Tom"
}
If you expect only a single result you can cast the it in Xpath:
$id = $xpath->evaluate(
"string(//subject[relation/@role='".$role."']/@id)"
);
var_dump($id);
Output:
string(3) "Tom"
Looking at the example posted in the comment your XML uses the namespace http://cpee.org/ns/organisation/1.0
without a prefix. The XML parser will resolve it so you can read the nodes as {http://cpee.org/ns/organisation/1.0}subject
. Here are 3 examples that all resolve to this:
<subject xmlns="http://cpee.org/ns/organisation/1.0"/>
<cpee:subject xmlns:cpee="http://cpee.org/ns/organisation/1.0"/>
<c:subject xmlns:c="http://cpee.org/ns/organisation/1.0"/>
The same has to happen for the Xpath expression. However Xpath does not have
a default namespace. You need to register an use an prefix of your choosing. This
allows the Xpath engine to resolve something like //org:subject
to //{http://cpee.org/ns/organisation/1.0}subject
.
The PHP does not need to change much:
$xml = <<<'XML'
<subject id="Tom" xmlns="http://cpee.org/ns/organisation/1.0">
<relation unit="ITSupport" role="ITSupporter" />
</subject>
XML;
$role = 'ITSupporter';
$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);
// register a prefix for the namespace
$xpath->registerNamespace('org', 'http://cpee.org/ns/organisation/1.0');
$ids = [];
// address the elements using the registered prefix
$idAttributes = $xpath->evaluate("//org:subject[org:relation/@role='".$role."']/@id");
foreach ($idAttributes as $idAttribute) {
$ids[] = $idAttribute->value;
}
var_dump($ids);