微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

php xpath with text()和SimpleXMLElement-> xpath不符合xpath预期结果

我正在尝试获取/ td / span的所有文本节点.

我正在尝试使用xpath / td / span / text()

问题是它返回每个文本元素的所有文本节点(这里有两个,“193”和“120”,它返回“193120”两次,而不是193和120在单独的元素中).

我在任何在线工具上尝试完全相同的xpath,它工作正常,在PHP中,完全不同的结果.

使用SimpleXMLElement

$xhtmlSnippet = '<td><span>193<span>10</span><span></span><div>66</div><span>195</span><span>.</span><span>34</span><span>242</span><span></span>120<span>64</span></span></td>';

$xml = new SimpleXMLElement($xhtmlSnippet);

$xresult = $xml->xpath('/td/span/text()');    

foreach($xresult as $xnode){
    echo "<br /><br />NodeValue: " . $xnode;
}

给我:

NodeValue: 193120

NodeValue: 193120

以下是通过在线工具正常工作的示例(所有其他在线工具也提供预期输出):

Working example in online tester

编辑:

使用DOMDocument DOMXPath,它似​​乎按预期工作:

    $dom = new DOMDocument;
    $dom->loadXML($xhtmlSnippet);

    $xpath = new DOMXPath($dom);

    foreach ($xpath->query('/td/span/text()) as $textNode) {
        echo "\n\nTextNode: " . $textNode->nodeValue;
    }

得到:

TextNode: 193

TextNode: 120

解决方法:

SimpleXMLElement只能单独表示元素和属性,或者表示相同类型的兄弟集合. ->xpath() method返回一个SimpleXMLElement对象数组,允许它们为非兄弟对象,但不允许任何其他节点类型.

因此,表达式/ td / span / text()匹配两个文本节点,但将它们作为表示其父元素的对象返回,在这种情况下恰好相同< span>元素,两次给你一个具有相同对象的数组.

这个难题的其余部分是当你将SimpleXML元素转换为字符串时,它将所有直接后代文本和CDATA节点组合成一个字符串,因此193和120会粘在一起.

因此输出是193120,两次.

(这绝对是不直观的行为,虽然很难知道SimpleXML在这种情况下应该做什么;如果XPath表达式解析为元素或属性以外​​的其他东西,最好产生错误).

由于DOM API具有可能存在于XML中的每种节点的对象,并且PHP包含该API的完整实现,因此XPath表达式将按预期工作.更重要的是,SimpleXML和DOM对象实际上都是围绕相同内部存储器结构的包装器,因此您可以使用dom_import_simplexml()和simplexml_import_dom()编写组合这两者的操作.

作为一个稍微不优雅的示例,如果您想在已经使用SimpleXML遍历的元素的上下文中运行XPath表达式,您可以执行以下操作:

$dom_node = dom_import_simplexml($simplexml_node);
$dom_xpath = new DOMXPath($dom_node->ownerDocument);
$dom_xpath_result = $dom_xpath->query('span/text()', $dom_node);

foreach($dom_xpath_result as $xnode){
    echo "<br /><br />NodeValue: " . $xnode->nodeValue;
}

显然,你可以根据需要将它包装成一个函数.还要注意,因为你的表达式从文档根开始(前导/),实际上下文是无关紧要的,这就是为什么我在上面使用了略微不同的表达式.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐