我正在尝试获取 /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;
}
给我:
节点值:193120
节点值:193120
这是一个通过在线工具正常工作的示例(所有其他在线工具也给出了预期的输出):
EDIT:
使用 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;
}
Gives:
文本节点:193
文本节点:120
SimpleXMLElement 只能表示元素和属性,可以单独表示,也可以表示相同类型同级元素的集合。这->xpath() method http://php.net/manual/en/simplexmlelement.xpath.php返回 SimpleXMLElement 对象的数组,这允许它们是非兄弟节点,但不允许任何其他节点类型。
因此,表达式/td/span/text()
匹配两个文本节点,但将它们作为表示其父元素的对象返回,在本例中,父元素恰好是相同的<span>
元素,为您提供一个两次包含相同对象的数组。
难题的剩余部分是,当您将 SimpleXML 元素转换为字符串时,它会将其所有直接后代文本和 CDATA 节点合并到一个字符串中,因此193
and 120
粘在一起。
因此输出是193120
, twice.
(这绝对是不直观的行为,尽管很难完全知道 SimpleXML 在这种情况下应该做什么;如果 XPath 表达式解析为元素或属性以外的其他内容,也许最好生成一个错误)。
由于 DOM API 具有 XML 中可能存在的每种节点的对象,并且 PHP 包含该 API 的完整实现,因此 XPath 表达式将按预期工作。更重要的是,SimpleXML 和 DOM 对象实际上都是相同内部内存结构的包装器,因此您可以使用将两者结合起来编写操作dom_import_simplexml()
and 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;
}
显然,您可以根据需要将其包装到一个函数中。另请注意,由于您的表达式从文档根开始(前导/
)实际的上下文是无关紧要的,这就是为什么我在上面使用了稍微不同的表达方式。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)