【问题标题】:Get DOMXpath results below previous result in HTML在 HTML 中获取低于先前结果的 DOMXpath 结果
【发布时间】:2012-12-05 05:13:47
【问题描述】:

我正在尝试对外部网站的 HTML 进行排序,但不幸的是,该网站的组织非常糟糕。数据可能如下所示:

<a class="title">Title One</a>
<a class="item">Item One</a>
<a class="item">Item Two</a>

<a class="title">Title Two</a>
<a class="item">Item One</a>
<a class="item">Item Two</a>    

我正在使用这样的 xpath 查询来获取标题:

$titles = $x->evaluate('//a[@class="title"]');

现在,我想列出标题及其下方的项目。不幸的是,这些元素都没有方便地包装在父 div 中,所以我不能只过滤父 div 中的所有内容。所以,我对这些项目使用这样的查询:

$titles = $x->evaluate('//a[@class="item"]');

理想情况下,我想做的只是检查当前标题元素下方的结果。所以,如果我循环并点击“标题一”,我只想检查出现在标题一和标题二之间的“项目”结果。有没有办法做到这一点?

这里不能修改 HTML。我知道这个问题有点荒谬,我的解释可能很糟糕,但如果有解决方案,它真的会帮助我!

谢谢大家。

【问题讨论】:

    标签: php domdocument domxpath


    【解决方案1】:

    你可以先找到标题元素,然后使用-&gt;nextSibling()继续前进:

    $html =<<<EOM
    <a class="title">Title One</a>
    <a class="item">Item One</a>
    <a class="item">Item Two</a>
    
    <a class="title">Title Two</a>
    <a class="item">Item One</a>
    <a class="item">Item Two</a>
    EOM;
    
    $d = new DOMDocument;
    $d->loadHTML($html);
    $x = new DOMXPath($d);
    foreach ($x->query('//a[@class="title"]') as $node) {
        echo "Title: {$node->nodeValue}\n";
        // iterate the siblings
        while ($node = $node->nextSibling) {
           if ($node->nodeType != XML_ELEMENT_NODE) {
                continue; // skip text nodes
            }
            if ($node->getAttribute('class') != 'item') {
                // no more .item
                break;
            }
            echo "Item: {$node->nodeValue}\n";
        }
    }
    

    输出:

    Title: Title One
    Item: Item One
    Item: Item Two
    Title: Title Two
    Item: Item One
    Item: Item Two
    

    【讨论】:

    • 非常感谢,这太棒了!
    【解决方案2】:

    您希望选择 &lt;a&gt; 元素的所有后续同级元素,其中 class="title" 再次是 &lt;a&gt; 元素但具有 class="item" 并且具有前面的第一个同级 &lt;a&gt; 元素 class="title" 是您开始查看的确切第一个元素。

    例如例如,在 xpath 中,您正在寻找第一个 title 元素:

    //a[class="title"][1]
    

    对于该元素,item 元素如下:

    //a[@class="title"][1]
        /following-sibling::a[
          @class="item" 
          and preceding-sibling::a[@class="title"][1] 
              = //a[@class="title"][1]
        ]
    

    如果你想在代码中使用它,你可以通过为标题元素创建一个相对表达式并使用DOMelement::getNodePath()

    $titles = $xp->query('//a[@class="title"]');
    foreach ($titles as $title)
    {
        echo $title->nodeValue, ":\n";
        $query = './following-sibling::a[@class="item" and 
                  preceding-sibling::a[@class="title"][1] = ' .
                  $title->getNodePath() . ']';
        foreach ($xp->query($query, $title) as $item)
        {
            echo ' * ', $item->nodeValue, "\n";
        }    
    }
    

    输出:

    Title One:
     * Item One
     * Item Two
    Title Two:
     * Item Three
     * Item Four
    

    【讨论】:

      猜你喜欢
      • 2012-05-10
      • 1970-01-01
      • 1970-01-01
      • 2014-05-26
      • 1970-01-01
      • 2012-05-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多