如何在DOMNode上执行XPath查询?

arv*_*sim 20 php dom

有没有办法在DOMNode上进行xpath查询?或者至少将其转换为DOMXPath?

<html>
  ...
  <div id="content">
     ...
     <div class="listing">
         ...
         <div></div>
         <div></div>
         <div  class='foo'>
           <h3>Get me 1</h3>
           <a>and me too 1</a>
         </div>
     </div>
     <div class="listing">
         ...
         <div></div>
         <div></div>
         <div class='foo'>
           <h3>Get me 2</h3>
           <a>and me too 1</a>
         </div>
     </div>
     ....
  </div>
</html>
Run Code Online (Sandbox Code Playgroud)

这是我的代码.我试图获得一个数组列表,其中包含h3的值和每个数组中的标签.为此,我需要获取每个列表,然后在每个列表中获取h3和标记的值.

$html_dom = new DOMDocument();
@$html_dom->loadHTML($html);
$x_path = new DOMXPath($html_dom);

$nodes= $x_path->query("//div[@id='content']//div[@class='listing']");

foreach ($nodes as $node)
{
  // I want to further dig down here using query on a DOMNode
}
Run Code Online (Sandbox Code Playgroud)

Gor*_*don 32

将节点作为第二个参数传递给 DOMXPath::query

contextnode:可以指定可选的contextnode来执行相对的XPath查询.默认情况下,查询是相对于根元素的.

例:

foreach ($nodes as $node) {
    foreach ($x_path->query('h3|a', $node) as $child) {
        echo $child->nodeValue, PHP_EOL;
    }
}
Run Code Online (Sandbox Code Playgroud)

这使用UNION运算符作为结果

Get me 1
and me too 1
Get me 2
and me too 1
Run Code Online (Sandbox Code Playgroud)

如果您不需要任何复杂的查询,您也可以这样做

foreach ($nodes as $node) {
    foreach ($node->getElementsByTagName('a') as $a) {
      echo $a->nodeValue, PHP_EOL;
    }
}
Run Code Online (Sandbox Code Playgroud)

或者甚至通过迭代子节点(请注意,这包括所有文本节点)

foreach ($nodes as $node) {
    foreach ($node->childNodes as $child) {
      echo $child->nodeName, PHP_EOL;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,所有这些都是不必要的,因为您可以直接获取这些节点:

$nodes= $x_path->query("/html/body//div[@class='listing']/div[last()]");

foreach ($nodes as $i => $node) {
    echo $i, $node->nodeValue, PHP_EOL;
}
Run Code Online (Sandbox Code Playgroud)

将给出所有div的最后一个div子节点中的两个节点,其中class属性值为listing,并输出组合的文本节点值,包括空格

0
           Get me 1
           and me too 1

1
           Get me 2
           and me too 1
Run Code Online (Sandbox Code Playgroud)

同样,以下内容

"//div[@class='listing']/div[last()]/node()[name() = 'h3' or name() = 'a']"
Run Code Online (Sandbox Code Playgroud)

会给你四个子H3和A节点和输出

0Get me 1
1and me too 1
2Get me 2
3and me too 1
Run Code Online (Sandbox Code Playgroud)

如果您需要在迭代它们时按名称区分这些,您可以这样做

foreach ($nodes as $i => $node) {
    echo $i, $node->nodeName, $node->nodeValue, PHP_EOL;
}
Run Code Online (Sandbox Code Playgroud)

然后会给

0h3Get me 1
1aand me too 1
2h3Get me 2
3aand me too 1
Run Code Online (Sandbox Code Playgroud)


EPB*_*EPB 10

提供您$node的上下文节点.

foreach ($nodes as $node)
{
   $morenodes = $x_path->query(".//h3", $node);
}
Run Code Online (Sandbox Code Playgroud)

请参阅$contextnode手册:http://php.net/manual/en/domxpath.query.php

  • 我继续编写了一个我最初用来测试我的答案的示例查询.如果你打算使用`//`来启动查询,那么从`.`开始很重要,这显然总是相对于root. (6认同)

Fei*_*Fei 6

为了使其完整,有一个DOMNode::getNodePath方法返回该节点的 xpath。所以你也可以使用$x_path->query($node->getNodePath().'//h3')