1

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>[email protected]</email>
    </user>
    <user>
        <name>Tyler</name>
        <email>[email protected]</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 );
3
  • DOMXPath argument should be type of DOMDocument not xml file. Commented Jan 7, 2017 at 15:48
  • I missed two lanes in my code, DOMXPath has DOMDocument in the constructror @Mohammad Commented Jan 7, 2017 at 15:50
  • Remove // from //email Commented Jan 7, 2017 at 15:59

2 Answers 2

1

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

Sign up to request clarification or add additional context in comments.

2 Comments

With email now I get length 0 .
('./email', $context) would be more specific (thus error-proof) in many cases.
1

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>[email protected]</email>
    </user>
    <user>
        <name>Tyler</name>
        <email>[email protected]</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) "[email protected]"
string(14) "[email protected]"

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) "[email protected]"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.