PHP XPath search returns 0 results

Below I have a PHP script that I need to search through an XML file and find the identifier for <AnotherChild> . For some reason, it currently returns 0 results, and I can't figure out why. If anyone can understand why it is returning 0 results, I would really appreciate it if they could tell me why.

XML:

 <TransXChange xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.transxchange.org.uk/" xsi:schemaLocation="http://www.transxchange.org.uk/ http://www.transxchange.org.uk/schema/2.1/TransXChange_general.xsd" CreationDateTime="2013-07-12T18:12:21.8122032+01:00" ModificationDateTime="2013-07-12T18:12:21.8122032+01:00" Modification="new" RevisionNumber="3" FileName="swe_44-611A-1-y10.xml" SchemaVersion="2.1"> <Node1>...</Node1> <Node2>...</Node2> <Node3>...</Node3> <Node4>...</Node4> <Node5>...</Node5> <Node6>...</Node6> <Node7> <Child> <id>ABCDEFG123</id> </Child> <AnotherChild> <id>ABCDEFG124</id> </AnotherChild> </Node7> <Node8>...</Node8> </TransXChange> 

PHP:

 <?php $xmldoc = new DOMDocument(); $xmldoc->load("directory1/directory2/file.xml"); $xpathvar = new DOMXPath($xmldoc); $xpathvar->registerNamespace('transXchange', 'http://www.transxchange.org.uk/'); $queryResult = $xpathvar->query('//AnotherChild/id'); foreach($queryResult as $result) { echo $result->textContent; } ?> 

thanks

+6
source share
2 answers

Two questions related to the comments do answer this question, but they do not make it clear why they answer IMO, so I will add my next answer in the chat .


Consider the following XML document:

 <root> <child> <grandchild>foo</grandchild> </child> </root> 

This attribute has no xmlns attributes, which means you can request //grandchild and get the expected result. Each node is in the default namespace, so everything can be solved without registering the namespace in XPath.

Now consider the following:

 <root xmlns="http://www.bar.com/"> <child> <grandchild>foo</grandchild> </child> </root> 

This declares the namespace http://www.bar.com/ , and as a result, you should use this namespace to address the node element.

As you already understood, the way to do this is to use DOMXPath::registerNamespace() - but the crucial point you missed is that (in the PHP XPath implementation) each namespace must be registered with a prefix, and you should use this prefix to address nodes belonging to him. Cannot register namespace in XPath with empty prefix.

So, given the second example above, let's see how to execute the original request //grandchild :

 <?php $doc = new DOMDocument(); $doc->loadXML($xml); $xpath = new DOMXPath($doc); $xpath->registerNamespace('bar', 'http://www.bar.com/'); $nodes = $xpath->query('//bar:grandchild'); foreach($nodes as $node) { // do stuff with $node } 

Notice how we registered the namespace using its URI and specified the prefix. Although the source XML does not contain this prefix, we use the prefix in the request - an example .

To understand why, consider another piece of XML:

 <baz:root xmlns:baz="http://www.bar.com/"> <baz:child> <baz:grandchild>foo</baz:grandchild> </baz:child> </baz:root> 

This document is semantically identical to the second - the sample code will work equally well with ( proof ). The prefix is ​​separate from the namespace. Note that although the document uses the baz: prefix, XPath uses the bar: prefix. This is because the thought that identifies the namespace is a URI, not a prefix.

Therefore, when a document uses a namespace, we must work with the namespace, and not against it, registering the namespace in XPath and using the prefix that we registered to refer to any nodes belonging to this namespace.

For completeness, when we apply these principles to your original document, the request that you will use with the code in the question is as follows:

 //transXchange:AnotherChild/transXchange:id 
+9
source

To fix this problem, I registered the namespace first:

 $xpathvar->registerNamespace('transXchange', 'http://www.transxchange.org.uk/'); 

And then changed the request as follows:

 $queryResult = $xpathvar->query('//transXchange:AnotherChild/transXchange:id'); 

This successfully returned the identifier.

+2
source

Source: https://habr.com/ru/post/951352/


All Articles