【问题标题】:Counting the Number of TH's in each Table using XPath使用 XPath 计算每个表中 TH 的数量
【发布时间】:2019-04-03 00:00:30
【问题描述】:

在尝试解析 HTML 文件时陷入困境。

基础知识:

$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTMLFile('myfile.html');
$xp = new DOMXPath($dom);

在这个初始化之后,我的技术是使用 XPATH 查询来获取我想要的变量。

如果有一个特定的项目或节点,我真的没有任何问题 - 非常容易查明和检索。

所以在我加载的 HTML 中,它基本上是在一个循环中形成的。缩小后看起来像这样:

<div class="intro">
    <div class="desc-wrap">
        Text Text Text
    </div>
    <div class="main-wrap">
        <table class="table-wrap">
            <tbody>
                <tr>
                    <th class="range">Range </th>
                    <th>#1</th>
                    <th>#2</th>
                </tr>
            </tbody>
        </table>
    </div>
</div>
<div class="intro">
    <div class="desc-wrap">
        Text Text Text
    </div>
    <div class="main-wrap">
        <table class="table-wrap">
            <tbody>
                <tr>
                    <th class="range">Range </th>
                    <th>#1</th>
                    <th>#2</th>
                    <th>#3</th>
                    <th>#4</th>
                </tr>
            </tbody>
        </table>
    </div>
</div>

这会持续 100 次(意味着 100 个 &lt;div class="intro"&gt; . . . &lt;/div&gt; 实例

所以我试图获取desc-wrap 的内容(那里没问题)、文本节点以及每个表中有多少&lt;th&gt; 的计数。

考虑到一个 XPath 查询可能比两个更好,我查询了 div。

$intropath = $xp->query("//div[@class='intro']");

循环播放。

$f=1;
foreach ($intropath as $sp) {
echo $f++ . '<br />'; // Makes it way to 100, good.

我遇到的问题/核心问题是尝试计算每个表中 &lt;th&gt; 的数量。

$gettables = $xp->query("//div[contains(@class,'main-wrap')]/table[contains(@class, 'table-wrap')]//th", $sp);
var_dump($getsizes); // public 'length' => int 488
// Okay, so this is getting all the <th> elements in the 
// entire document, not just in the loop. Maybe not what I want.

这是我尝试过的其他方法(我的意思是失败了)

好吧,让我们尝试只针对第一个表(在//th 之前添加[0]),看看我们能不能得到一些东西。

$gettables = $xp->query("//div[contains(@class,'main-wrap')]/table[contains(@class, 'table-wrap')][0]//th", $sp);

不。非对象。长度 0。不知道为什么。好的,让我们把它取下来。

也许试试这个?

//div[contains(@class,'main-wrap')]/table[contains(@class, 'table-wrap')]//th[count(following-sibling::*)]

好的。所以长度 = 100。必须得到一个 th 并进行推断。不是我想要的。

也许只是

//th[count(*)]

不。非对象。

也许是这个?

count(//div[contains(@class,'main-wrap')]/table[contains(@class, 'table-wrap')]//th)

不。更多非对象。

这可能已经足够我尝试过的例子了。 失败很有趣(好吧,学习),但我错过了什么? 我的输出...我只想找出每个表中有多少&lt;th&gt;

所以,比如:

foreach ($intropath as $sp) {
$xpath = $xp->query("//actual/working/xpath/for/individual/th");
$thcount = count($getsizes->item(0)); // or something?
echo $thcount . '<br>';

在上面的例子中,会输出

3

5

当然还要继续其他 98 次迭代..

这可能很愚蠢。我一直在引用这个cheatsheet 和这个cheatsheet,我学到了很多关于XPATH 的功能,但是这个答案是在暗示我。在这一点上,我什至不确定做我的foreach ($intropath as $sp) { 是否是实现我正在做的事情的正确方法。

有人想把我从这个坑里挖出来,这样我就可以继续下一步和/或我的生活了吗?

【问题讨论】:

    标签: php dom xpath


    【解决方案1】:

    使用迭代的query() 调用计算符合条件的节点。

    代码:(Demo)

    $dom = new DOMDocument();
    libxml_use_internal_errors(true);
    $dom->loadHTML($html);
    $xp = new DOMXPath($dom);
    foreach ($xp->query("//div[contains(@class,'main-wrap')]/table[contains(@class, 'table-wrap')]//tr") as $node) {
        echo $xp->query("th", $node)->length , "\n";
    }
    

    输出:

    3
    5
    

    【讨论】:

    • 是的!最后。 :) 这是有效的,谢谢。更深入地研究它。请问我是否需要在自己的foreach 循环中执行此操作,如您的回答所示,或者我可以(或应该?)在我原来的foreach 循环中使用 div 执行此操作?
    • 您可以像这样扩展第一个查询://div[@class='intro']/div[contains(@class,'main-wrap')]/table[contains(@class, 'table-wrap')]//tr 如果您要问的话。您不需要三个嵌套循环。演示:3v4l.org/79WXu
    • (所以你知道我已经支持了你的问题)感谢您的支持/接受。破解20K!现在我很高兴/很难过——我认为那是最后一个里程碑——不是。成瘾/追求仍在继续。
    • 不,我的朋友,你明白了。我只是在弄乱这一切的碎屑。它会结束吗?但愿如此。很高兴我能帮你推倒你。很遗憾听到它并没有像许多大师过去所说的那样把你变成一个开明的编码之神。也许40K? :)
    • @mickmackusa 是的,但你知道,当你拿到那个时,你会一直想知道大约 200k...
    【解决方案2】:

    首先查询tables:

    $intropath = $xp->xpath("//table[contains(@class, 'table-wrap')]");
    

    然后使用另一个 XPath 查询和应用于所有 ths 的 count PHP 函数来获取每个 tableths 计数与上下文节点相关:

    foreach ($intropath as $tab) {
      $count = count($tab->xpath(".//th"));
      echo $count . "<br>";
    }
    

    这应该就是全部了。

    附注:
    显然 PHP 不喜欢 XPath count 函数,所以我改用 PHP count 函数。


    为了完整性:
    如果可以使用 XPath-2.0,下面的表达式会更简洁:

    string-join(//table[contains(@class, 'table-wrap')]/count(.//th),'#')
    

    这里,# 是每个 tables 计数之间的分隔符。

    【讨论】:

    • 您可以在foreach 查询键上执行另一个query 吗?没有意识到。无论哪种方式,它都不起作用..在$intropath上执行var_dump会返回240的长度...在$tab上执行var_dump会在textContent中引入th内容。 .但我看不到计算th的数量的渠道。无论如何,按原样执行代码我只是得到Fatal error: Uncaught Error: Call to undefined method DOMElement::query()$count 行..
    • 好的。我没有测试过。对此感到抱歉。我将答案更改为另一个 -&gt;xpath 查询。
    • 没问题。感谢任何可能的帮助。不知道为什么它不起作用。第一个,我改变了......现在我刚刚得到Fatal error: Uncaught Error: Call to undefined method DOMElement::xpath() ...第二个......看起来很酷,但仍在测试:)(老实说XPath-2.0,我不知道:P - 或如果我有它,或者它需要在一个循环中或它自己。现在我只是得到false 的一切所以......
    • -&gt;xpath 是否仅适用于 XML 文件?不确定。我认为这可能是问题所在,我正在尝试解析 HTML/DOM。添加到 $intropath 会显示相同的错误。令人困惑……嗯……我在 PHP 7.1.16 上……我需要扩展吗?试图解决这个问题:P
    • 我将 count 函数从 XPath 更改为 PHP,现在它可以正常工作了。我用http://phptester.net/ PHP 7.0 版测试了它。
    猜你喜欢
    • 2013-12-28
    • 2019-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-02
    • 2013-02-06
    • 1970-01-01
    相关资源
    最近更新 更多