使用QueryPath在foreach中使用多个find

时间:2011-12-06 02:30:09

标签: php querypath

我正在使用QueryPath和PHP。

这可以找到.eventdate,但不会为.dtstart返回任何内容:

$qp = htmlqp($url);
foreach ($qp->find('table#schedule')->find('tr') as $tr){
    echo 'date: ';
    echo $tr->find('.eventdate')->text();
    echo ' time: ';
    echo $tr->find('.dtstart')->text();
    echo '<br>';
}

如果我交换这两个,.dtstart工作正常,但.eventdate不会返回任何内容。因此,似乎querypath中的find()会破坏元素并仅返回它所需的值,使迭代超过$ tr无法搜索多个项目。

以下是我正在处理的TR的示例HTML:

<tr class="event"><th class="date first" scope="row"><abbr class="eventdate" title="Thursday, February 01, 2011" >02/01</abbr><span class="eventtime" ><abbr class="dtstart" title="2012-02-01T19:00:00" >7:00 PM</abbr><abbr class="dtend" title="2012-02-01T21:00:00" >9:00 PM</abbr></span></th><td class="opponent summary"><ul><li class="first">@ <a class="team" href="/high-schools/ridge-wolves/basketball-winter-11-12/schedule.htm" >Ridge </a> <span class="game-note">*</span></li><li class="location" title="Details: Ridge High School">Details: Ridge High School</li><li class="last"><a class="" href="/local/stats/pregame.aspx?contestid=4255-4c6c-906d&amp;ssid=381d-49f5-9f6d" >Preview Game</a></li></ul></td><td class="result last"><a class="pregame" href="/local/stats/pregame.aspx?contestid=4255-4c6c-906d&amp;ssid=381d-49f5-9f6d">Preview</a></td></tr>

我尝试在第一次找到之前复制$ tr并在第二次找到之前将其替换掉,但这不起作用。

如何在每个$ tr期间搜索某些变量?

仅供参考,除了.eventdate和.dtstart之外,我还想在对象的a和。a锚文本下使用.opponent,href。

3 个答案:

答案 0 :(得分:9)

出于性能原因,QueryPath在内部维护其状态(与jQuery不同)。所以branch()是要走的路。

作为对提议的解决方案的修改,我建议通过这样做来最小化find()调用的数量:

$qp = htmlqp($url);
foreach ($qp->find('table#schedule tr') as $tr){
    echo 'date: ';
    echo $tr->branch('.eventdate')->text();
    echo ' time: ';
    echo $tr->branch('.dtstart')->text();
    echo '<br>';
}

最后,每当您执行“破坏性”操作(例如find())时,您始终可以使用end()返回一步。所以上面也可以这样做:

$qp = htmlqp($url);
foreach ($qp->find('table#schedule tr') as $tr){
    echo 'date: ';
    echo $tr->find('.eventdate')->text();
    echo ' time: ';
    echo $tr->end()->find('.dtstart')->text();
    echo '<br>';
}

这是一个非常非常小的性能改进,但我更喜欢branch()方法,除非我正在处理大于1M的文档。

在QueryPath 3.x中,它有一大堆新的性能增强功能,我正在考虑使用jQuery方法为每个函数创建一个新对象。不幸的是,这种方法将使用更多的内存,所以我可能不会保留它。虽然branch()需要一点时间来学习,但它确实有其优势。

答案 1 :(得分:8)

我只是自己学习QueryPath,但我认为你应该分支行对象。否则,$tr->find('.eventdate')会将您带到行中包含的abbr元素,并且find()后面的每个元素都会尝试查找abbr下方的元素,从而导致无匹配。 branch()(请参阅documentation)创建QueryPath对象的副本,使原始对象(在本例中为$tr)保持不变。

所以你的代码是:

$qp = htmlqp($url);
foreach ($qp->find('table#schedule')->find('tr') as $tr){
    echo 'date: ';
    echo $tr->branch()->find('.eventdate')->text();
    echo ' time: ';
    echo $tr->branch()->find('.dtstart')->text();
    echo '<br>';
}

我不知道这是否是达到你想要的首选方式,但它似乎有效。

答案 2 :(得分:0)

是的你是对的,我今天实际上遇到了这个问题,在jquery中,你只是查询,查询,查询,查询没有问题,但是如果你查询QueryPath,它会改变对象的内部“状态”,所以如果你尝试第二个查询,它是针对当前状态应用的。

因此,如果要查询文档中的多个“单独”位置,则必须在

之前进行分支

$ q = qp(“something.html);
$ a = $ q-&gt; branch() - &gt; find(“tr”);
$ b = $ q-&gt; branch() - &gt; find(“a”);

这似乎适用于我的代码,因此我认为它适用于您的代码。