简体   繁体   中英

How to find element in specific context using DOMXPath in php?

I'm trying to parse a xml file with information about some users. Something like this

users.xml

<?xml version="1.0" encoding="UTF-8"?>
<users>
    <user>
        <name>Alexander</name>
        <email>alexander@test.com</email>
    </user>
    <user>
        <name>Tyler</name>
        <email>tyler@test.com</email>
    </user>
</users>

I'm using DOMXpath to extract all users inside this xml, and all of this fields. In xml file, I have 15 users and when I search all fields about one user in this code

$username = $xpath->query ( '//email', $users->item(0) );

I got 15 length, instead of 1. I mean query is searching in all xml instead of looking for the actual user. What I'm doing wrong?

xml_query.php

$xml = new DOMDocument();
$xml->loadXML( $xml_content );
$xpath = new DOMXPath($xml);

$users = $xpath->query( '//user' );
var_dump( $users->item(0) );
$username = $xpath->query ( '//email', $users->item(0) );

var_dump( $username );

Because //email select all elements in the document but you need to select elements within the current context. Remove // from query expression.

$username = $xpath->query ( 'email', $users->item(0) );

See result in demo

A slash ( / ) at the start of an location path makes it relative to the document node. The context node will be ignored. If it is followed by another slash, it uses the descendant axis. //email is short for /descendant::email . The default axis is child .

$xml = <<<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<users>
    <user>
        <name>Alexander</name>
        <email>alexander@test.com</email>
    </user>
    <user>
        <name>Tyler</name>
        <email>tyler@test.com</email>
    </user>
</users>
XML;

$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
foreach ($xpath->evaluate('//user') as $user) {
  var_dump($xpath->evaluate('string(email)', $user));
}

Output:

string(18) "alexander@test.com"
string(14) "tyler@test.com"

DOMXpath::evaluate() can return node lists or scalars depending on the expression. It allows you to cast the nodes to string directly in the Xpath expression.

Xpath expression can contain conditions so to output the email by position you could do something like:

foreach ($xpath->evaluate('//user[2]') as $user) {
  var_dump($xpath->evaluate('string(email)', $user));
}

Output:

string(14) "tyler@test.com"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM