是否有一种简单的方法可以使用DomDocument和DomXPath获取子元素?


Is there an easy way to get subelements with DomDocument and DomXPath?

假设我有这样的HTML:

<div id="container">
    <li class="list">
        Test text
    </li>
</div>

我想得到li的内容。

我可以使用以下代码获取容器div的内容:

$html = '
<div id="container">
    <li class="list">
        Test text
    </li>
</div>';
$dom = new 'DomDocument;
$dom->loadHTML($html);
$xpath = new 'DomXPath($dom);
echo $dom->saveHTML($xpath->query("//div[@id='container']")->item(0));

我希望我可以通过简单地将子元素的内容添加到查询(就像你如何在simpleHtmlDom中做到这一点):

echo $dom->saveHTML($xpath->query("//div[@id='container'] li[@class='list']")->item(0));

但是抛出了一个警告(后跟致命错误),说:

 Warning: DOMXPath::query(): Invalid expression ...

我知道做我想做的事情的唯一方法是:

$html = '
<div id="container">
    <li class="list">
        Test text
    </li>
</div>';
$dom = new 'DomDocument;
$dom->loadHTML($html);
$xpath = new 'DomXPath($dom);
$dom2 = new 'DomDocument;
$dom2->loadHTML(trim($dom->saveHTML($xpath->query("//div[@id='container']")->item(0))));
$xpath2       = new 'DomXPath($dom2);
echo $xpath2->query("//li[@class='list']")->item(0)->nodeValue;

然而,这是一个可怕的大量代码只是为了获得li的内容,问题是,作为项目嵌套更深(如如果我想获得'div#container ul。container li.list)我必须继续添加越来越多的代码。

对于simpleHtmlDom,我所要做的就是:
$html->find('div#container li.list', 0);

我错过了用DomDocument和DomXPath做事情的更简单的方法,还是真的这么难?

你的第一次尝试很接近;您的语法有一个字符错误。试试下面的XPath:

//div[@id='container']/li[@class='list']

你可以看到在div节点和li节点之间有一个空格,那里应该有一个正斜杠

SimpleHTMLDOM使用CSS选择器,而不是Xpath。CSS选择器中的任何东西也可以用Xpath完成。DOMXpath::query()只支持返回节点列表的Xpath表达式,但是Xpath也可以返回标量。

在Xpath中,/用于分隔位置路径的各个部分,而不是空格。它还有两个附加含义。位置路径开始处的/使其成为绝对的(它从文档开始,而不是当前上下文节点)。第二个/是后代轴的简短语法。

试题:

$html = '
<div id="container">
    <li class="list">
        Test text
    </li>
</div>';
$dom = new 'DomDocument;
$dom->loadHTML($html);
$xpath = new 'DomXPath($dom);
echo trim($xpath->evaluate("string(//div[@id='container']//li[@class='list'])"));
输出:

Test text

在CSS选择器序列中,空格是两个选择器的组合符。

  • css: foo bar
  • Xpath简短语法://foo//bar
  • Xpath完整语法:/descendant::foo/descendant::bar

另一个组合子是>。这个轴是Xpath中的默认轴。

  • css: foo > bar
  • Xpath简短语法://foo/bar
  • Xpath完整语法:/descendant::foo/child::bar