xpath循环到未知数量的节点

时间:2012-11-09 15:15:43

标签: php xpath html-parsing

我有一个看起来像这样的xpath:

$path = '//*[@id="page-content"]/table/tbody/tr[3]/td['.$i.']/div/a';

其中$i从1变为 X 。我会正常使用:

for($i=1; $i<X;$i++){
  $path = '//*[@id="page-content"]/table/tbody/tr[3]/td['.$i.']/div/a';
  $nodelist = $xpath->query($path);
  $result = $nodelist->item(0)->nodeValue;
};

然而,在这种情况下,我不知道 X 多少。有没有办法在不知道X的情况下循环这个?

4 个答案:

答案 0 :(得分:5)

为什么不叠加em?像(脆弱的代码,添加你的支票):

// first xpath for the outer node-list
$tds = $xpath->query('//*[@id="page-content"]/table/tbody/tr[3]/td');
foreach ($tds as $td)
{
    // fetch the included values with a relative xpath to the current node
    $nodelist = $xpath->query('./div/a', $td);
    ...
}

实际上你甚至不需要那个内部节点列表,因为你想在最后查询节点值。但是我在这里留下这个来展示你可以通过使用相对于具体节点的xpath直接做什么。


因此,如果您需要内的 {/ em> <a> <div> {/ 1>} <tr> 任何节点内任何表的“page-content”,您可以直接编写它,它是一个查询:

//*[@id="page-content"]/table/tbody/tr[3]/td/div/a[1]

谓词(即括号)仅适用于前缀为路径的节点,因此[1]仅适用于a,仅适用于[3]对于tr

代码示例:

$as = $xpath->query('//*[@id="page-content"]/table/tbody/tr[3]/td/div/a[1]');
foreach ($as as $a) 
{
    echo $a->nodeValue, "\n";
}

因此,这会将结果作为单个节点列表提供给您,您不需要运行第二个xpath查询。

答案 1 :(得分:2)

如果我理解你的问题,你问的是如何循环直到XPath下的<td>元素的最大数量?

您可以使用以下方法检索节点数:

count(//*[@id="page-content"]/table/tbody/tr[3]/td)并将其存储为临时变量,然后在下一个语句中使用它,如下所示:

for($i=1; $i<numberOfTdElements;$i++){
  $path = '//*[@id="page-content"]/table/tbody/tr[3]/td['.$i.']/div/a';
  $nodelist = $xpath->query($path);
  $result = $nodelist->item(0)->nodeValue;
};

回应hakre的建议:

$tbody = $doc->getElementsByTagName('tbody')->item(0);

// our query is relative to the tbody node
$query = 'count(tr[3]/td)';

$tdcount = $xpath->evaluate($query, $tbody);
echo "There are $tdcount elements under tr[3]\n";

然后将它们全部结合在一起:

for($i=1; $i<$tdcount;$i++){
      $path = '//*[@id="page-content"]/table/tbody/tr[3]/td['.$i.']/div/a';
      $nodelist = $xpath->query($path);
      $result = $nodelist->item(0)->nodeValue;
    };

答案 2 :(得分:0)

我认为您要做的是获取a的每个div元素,该元素又是td元素的子元素,轮流,是每个第三个​​ tr元素的子元素等。如果这是正确的,您只需使用此查询获取这些元素:

<?php 

$doc = new DOMDocument();
$doc->loadXML( $xml );
$xpath = new DOMXPath( $doc );
$nodes = $xpath->query( '//*[@id="page-content"]/table/tbody/tr[3]/td/div/a' );
foreach( $nodes as $node )
{
    echo $node->nodeValue . '<br>';
}

$xml是一个文档,类似于:

<?php

$xml = <<<XML
<?xml version="1.0" encoding="utf-8" ?>
<result>
    <div id="page-content">
        <table>
            <tbody>
                <tr>
                    <td>
                        <div><a>This one shouldn't be fetched</a></div>
                    </td>
                </tr>
                <tr>
                    <td>
                        <div><a>This one shouldn't be fetched</a></div>
                    </td>
                </tr>
                <tr>
                    <td>
                        <div><a>This one should be fetched</a></div>
                    </td>
                    <td>
                        <div><a>This one should be fetched</a></div>
                    </td>
                    <td>
                        <div><a>This one should be fetched</a></div>
                    </td>
                    <td>
                        <div><a>This one should be fetched</a></div>
                    </td>
                    <td>
                        <div><a>This one should be fetched</a></div>
                    </td>
                </tr>
                <tr>
                    <td>
                        <div><a>This one shouldn't be fetched</a></div>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</result>
XML;

换句话说,无需循环遍历所有这些td元素。您可以一次性获取它们,从而生成包含所有必需节点的DOMNodeList

答案 3 :(得分:0)

$doc = new DOMDocument();

$doc->loadXML( $xml );

$xpath = new DOMXPath( $doc );

$nodes = $xpath->query( '/result/div[@id="page-content"]/table/tbody/tr[3]/td/div/a');

foreach( $nodes as $node )
{
    echo $node->nodeValue . '<br>';
}