XML示例:
<node-root>
<node-1>
<node-2>
....
<node-1000>
<node-1001>
<node-1002>
text
</node-1002>
</node-1001>
</node-1000>
....
</node-2>
</node-1>
</node-root>
我想要的是在<node-1000>
之前检索文本节点的所有祖先。
我的XPath查询(PHP):
$parentNodes = $xpath->query("ancestor::*" , $textNode);
$textNode
是文本节点,其中包含text
。在PHP中,这意味着从该节点执行查询。
显然,这个表达式试图找到所有祖先,但这可能导致不必要的资源消耗。就我而言,我不想搜索比<node-1000>
更深的父节点。有没有办法在<node-1000>
之后停止查询执行。
假设我不知道在遇到<node-1000>
之前我应该执行多少步骤。所以不能使用它:../
答案 0 :(得分:1)
你应该可以使用
$parentNodes = $xpath->query("ancestor::*[node-1000]/*" , $textNode);
这将为您提供<node-1000>
元素或
$parentNodes = $xpath->query("ancestor::*[node-1000]//*" , $textNode);
(带// *),它将获取最多<node-1000>
的所有节点。
编辑:测试代码......
$data = <<< XML
<node-root>
<node-1>
<node-2>
....
<node-1000>
<node-1001>
<node-1002>
text
</node-1002>
</node-1001>
</node-1000>
....
</node-2>
</node-1>
<node-1>
<node-2>
....
<node-1000>
<node-a></node-a>
<node-c></node-c>
<node-100>
<n></n>
<node-1002>
text2
</node-1002>
</node-100>
</node-1000>
....
</node-2>
</node-1></node-root>
XML;
$xml = new DOMDocument();
$xml->loadXML($data);
$xpath = new DOMXPath($xml);
// Next line - use item(0) to pick first, 1 for second
$textNode = $xpath->query("//node-1002")->item(1)->childNodes[0];
echo $xml->saveXML($textNode);
$parentNodes = $xpath->query("ancestor::*[node-1000]//*" , $textNode);
echo count($parentNodes).PHP_EOL;
echo $xml->saveXML($parentNodes->item(0));
使用第二项输出......
text2
1
<node-1000>
<node-a/>
<node-c/>
<node-100>
<n/>
<node-1002>
text2
</node-1002>
</node-100>
</node-1000>
答案 1 :(得分:1)
用于选择高于或等于node-1000
的所有节点的XPath表达式是
ancestor::*[substring-after(local-name(),'node-')>=1000]
在PHP中,这看起来像
$parentNodes = $xpath->query("ancestor::*[substring-after(local-name(),'node-')>=1000]" , $textNode);
如果当前选定的节点$xpath
为node-1002
,则会选择node-1001
和node-1000
。
答案 2 :(得分:1)
在一般情况下(不假设您的示例的特定属性),让我们按如下方式说明问题:找到上下文节点的所有祖先,直到(并包括)名为X的第一个节点,其中X是静态的;我们假设我们不关心如果没有名为X的祖先会发生什么。
您正在使用PHP中的默认XPath处理器,因此您可能正在寻找XPath 1.0解决方案。
你可以在XPath 1.0中做的最好的事情是
ancestor::*[ancestor-or-self::X]
但它在深树中可能效率很低,因为对于每个祖先,你都在搜索它的所有祖先。
所以我可能会处理来自宿主语言的逻辑,并重复调用以获取当前节点的父节点,在找到X时停止搜索。
在XPath 3.1中你可以做到
let $X := ancestor-or-self::X[1]
return ancestor::*[. >> $X]
但是,在满足条件之前,反复寻找父母的效率仍然不高。
可悲的是,即使在XPath 3.1中,我们也没有&#34;直到&#34;运营商:ancestor::* until self::X
。我一直以为这会很有用,但从来没有设法为它提供足够的支持。 (一个复杂因素是你真的需要&#34;直到X包含&#34;和&#34;直到X exclusive&#34;变种。)
我们在XPath 3.1中拥有的是能够自己实现此操作符作为高阶函数:
let $until-inclusive := function($this, $next, $condition) {
if (exists($this))
then ($this, if ($condition($this)) then () else $next($this))
else ()}
return $until-inclusive(., function($p){$p/..}, function($q){$q[self::X]})
如果您正在使用支持高阶函数的XPath 3.1处理器(可以从PHP获得Saxon-PE ......)那么这可能是在XPath中实现它的最佳方式 - 但它&#39 ; s仍然可能更容易用宿主语言来做。