Traverse DOM向后发现id

时间:2013-12-18 16:06:27

标签: php dom xpath

我无法找到解决这个问题的方法

<div>
  <p id="p1"> Price is  <span>$ 25</span></p>
  <p id='p2'> But this price is $ <span id="s1">50,23</span> </p>
  <p id='p3'> This one :  $ 14540.12 dollar</p>
</div>

我要做的是找到一个价格合理的元素,这是它的最短路径。 这就是我所熟悉的。

$elements = $dom->getElementsByTagName('*');

foreach($elements as $child)
{
   if (preg_match("/.$regex./",$child->nodeValue)){
      echo $child->getNodePath(). "<br />";

   }
}

这导致

/html
/html/body
/html/body/div
/html/body/div/p[1]
/html/body/div/p[1]/span
/html/body/div/p[2]
/html/body/div/p[2]/span
/html/body/div/p[3]

这些是我想要的元素的路径,所以在这个测试HTML中没问题。但在真正的网页中,这些路径变得非常长并且容易出错。 我想要做的是找到具有ID属性的最接近的元素并参考它。

因此,一旦找到与$ regex匹配的元素,我需要向上移动DOM并找到第一个带有ID属性的元素并从中创建新的较短路径。 在上面的HTML示例中,有3个价格与$ regex相匹配。价格如下:

//p[@id="p1"]/span
//p[@id="s1"]
//p[@id="p3"]

这就是我希望从我的功能中返回的内容。我还需要摆脱存在的所有其他路径,因为它们不包含$ regex

对此有何帮助?

1 个答案:

答案 0 :(得分:0)

您可以使用XPath跟随祖先路径到包含@id属性的第一个节点,然后关闭其路径。没有清理代码,但是这样的话:

// snip
$xpath = new DomXPath($doc);
foreach($elements as $child)
{
    $textValue = '';
    foreach ($xpath->query('text()', $child) as $text)
        $textValue .= $text->nodeValue;
    if (preg_match("/.$regex./", $textValue)) {
        $path = $child->getNodePath();
        $id = $xpath->query('ancestor-or-self::*[@id][1]', $child)->item(0);
        $idpath = '';
        if ($id) {
            $idpath = $id->getNodePath();
            $path = '//'.$id->nodeName.'[@id="'.$id->attributes->getNamedItem('id')->value.'"]'.substr($path, strlen($idpath));
        }
        echo $path."\n";
   }
}

打印类似

的内容
/html
/html/body
/html/body/div
//p[@id="p1"]
//p[@id="p1"]/span
//p[@id="p2"]
//span[@id="s1"]
//p[@id="p3"]