我正在尝试对外部网站的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中,所以我不能只过滤父节点中的所有内容。所以,我对这些项目使用这样的查询:
$titles = $x->evaluate('//a[@class="item"]');
理想情况下,我想做的只是检查当前标题元素下面的结果。所以,如果我循环并点击“标题一”,我只想检查标题一和标题二之间出现的“项目”结果。有没有办法做到这一点?
此处无法修改HTML。我知道这个问题有点荒谬,我的解释可能很糟糕,但是如果有解决办法的话,那真的会帮助我!
谢谢大家。
答案 0 :(得分:1)
您可以先找到标题元素,然后使用->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
答案 1 :(得分:0)
您希望选择<a>
元素的所有后续兄弟姐妹,class="title"
元素再次为<a>
元素,但class="item"
且具有第一个前一个兄弟{ {1}} <a>
元素是您开始查看的第一个元素。
E.g。在xpath中,例如,您正在寻找第一个class="title"
元素:
title
对于该元素,//a[class="title"][1]
元素如下:
item
如果你想在代码中使用它,可以通过创建title元素的相对表达式并使用//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";
}
}