PHP DOM解析器 - 获取两个已知XPath之间的所有节点

问题描述:

如何选择两个已知XPath之间的所有DOM节点?PHP DOM解析器 - 获取两个已知XPath之间的所有节点

Xpath1 = html/body/div[2]/p 
Xpath2 = html/body/div[2]/p/a[3] 

DOM结构:

<html> 
<body> 
<div id="id3"> 
    <p id="p3"> 
     text1 
     <a href="#"> 
      goal 
     </a> 
     text2 
     <a href="#"> 
      Crowdrise 
     </a>. 
    </p> 
</div> 
</body> 
</html> 

分析器:

$dom = new DOMDocument(); 
$dom->loadHTML($domain); 

$x = new DOMXPath($dom); 
$el = $x->query("....??"); 

所以,基本上找一个查询方法来选择两个XPath之间的所有节点。 我看到了一些类似的问题,但它们似乎与XSLT案例有关。

+0

你是什么意思'之间'?如果你在树上选择2个分支,哪些分支在'之间?另外,XSLT使用XPath作为表达式语言,所以这些答案可能适用。 – Kenney

+0

XPath中没有分支。一切都是节点。如果有20个节点并选择7和15,则需要一种方法来选择节点7-15(含) – bbking7

+0

XPath是一种树寻址语言,而树的概念是分支的概念。你将如何订购这些节点1..20,准确的?这就是我的意思:如果我把所有的节点放在中间,我就必须知道从一个节点到另一个节点的路径。从最深的节点开始,我会提升一步(父节点),然后环顾四周,看看另一个节点是否是兄弟节点。但是,如果必须的话,您不会在任何树中的任何两个节点之间找到一条路径,也不会递归(下降到兄弟节点)。 – Kenney

不错的问题。 没有这样做的一般方法,因为它取决于第二个元素相对于第一个元素的位置。我的意思是,如果第二个元素是第一个元素的后代,或者它在另一个分支中 - 那两个完全不同。 所以我们需要做一个假设:

  • 让我们假设第二路径定义的第二个元素永远是确定的由第一路径的第一个元素的后代。

我们的目标是获得第一个元素的所有后代元素(没有文本节点),而没有第二个元素的共享后裔。

为了实现这个目标,我们需要的表达式:

el1 = All element 1 descendants. 
el2 = All element 2 descendants including self. 
result = el1 [position() <= count(el1) - count(el2)] 

正如你可以看到我们正在建立的一组前N个元素的直到到达第二元件。

下面是一个例子:

<?php 

$dom = new DOMDocument(); 
$dom->loadHTML('<html>' 
    . '   <body>' 
    . '    <div>' 
    . '     <h1>shlomi</h1>' 
    . '     <p>' 
    . '      <span>goal1</span>' 
    . '      text1' 
    . '      <a href="#">goal2</a>' 
    . '      text2' 
    . '      <a href="#"><span></span>Crowdrise</a>' 
    . '      .' 
    . '     </p>' 
    . '    </div>' 
    . '   </body>' 
    . '  </html>'); 

$x = new DOMXPath($dom); 

$path1 = "/html/body/div/p/descendant::*";    // all descendant elements without text 
$path2 = "/html/body/div/p/a[2]/descendant-or-self::*"; // all descendant elements without text including self 
$path3 = $path1."[position() <= count(".$path1.") - count(".$path2.")]"; 
$elList = $x->query($path3); 

foreach ($elList as $node) { 
     echo $node->nodeName." -> text: ".$node->textContent."<br />"; 
} 

会打印:

span -> text: goal1 
a -> text: goal2 

注意我使用*目标没有文本节点仅元素 - 如果你想要的所有节点更换与node()