简体   繁体   中英

PHP DOMXPath query seems to ignore contextnode parameter

I am trying to parse some HTML but have some problems with DOMXPath query function. I want my code to find all divs with class "container" and than in every one of them find a div with class "name". On http://php.net/manual/en/domxpath.query.php I read that you can specify contextnode for XPath query function to search only inside certian node, but in my case it doesen't seem to do anything.

This might be because $person is an object of type DOMElement and XPath query accepts DOMNode as contextnode. But as I understand DOMElement extends DOMNode, so that shouldn't be a problem. Also I don't get any errors or warnings.

I am using PHP version 5.5.12.

This is my code:

<pre>
<?php
$html = '
<div class="junk">...</div>
<div class="container">
    <div class="name">Kdksf</div>
    <div class="surname">Gskdl</div>
    <div class="junk">...</div>
</div>
<div class="container">
    <div>
        <div>
            <div class="name">Rada</div>
            <div class="surname">Ldsa</div>
        </div>
    </div>
    <div class="junk">...</div>
</div>
<div class="container">
    <div class="name">Sdfex</div>
    <div class="surname">Fdss</div>
    <div class="junk">...</div>
</div>
<div class="junk">...</div>
';

$doc = new DOMDocument();
libxml_use_internal_errors(true);
$doc->loadHTML($html);
$xpath = new DOMXPath($doc);
$persons = $xpath->query("//*[contains(@class, 'container')]");

foreach ($persons as $person) {
    $name = $xpath->query("//*[contains(@class, 'name')]", $person);

    print_r($name->item(0)->textContent);

    echo "<hr>";
}

?>

Expected output is:

Kdksf
Rada
Sdfex

But I get:

Kdksf
Kdksf
Kdksf

I cannot test it ATM, but you can achieve this with one XPath query:

$persons = $xpath->query("//*[contains(@class, 'container')]//div[@class='name']");

foreach ($persons as $person) {
    print_r($person->textContent);
    echo "<hr>";
}

The problem is that when you start using // you are saying that it can be any node, as DOM has links up and down the hierarchy, it gives XPath a free rain to find anything.

If instead you use

$name = $xpath->query("descendant::*[contains(@class, 'name')]", $person);

you are limiting the search to just descendants of the context node.

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