Подсчет количества TH в каждой таблице с использованием XPath - PullRequest
0 голосов
/ 30 октября 2018

Застрял в кроличьей норе, пытаясь разобрать файл 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 экземпляров <div class="intro"> . . . </div>

Итак, я пытаюсь получить содержимое desc-wrap (без проблем), текстовые узлы, а также подсчет количества <th> в каждой таблице.

Подумав, что один запрос XPath может быть лучше, чем два, я делаю запрос к div.

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

Loop it.

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

Мой вопрос / основная проблема, которую я имею, пытается подсчитать количество <th> в каждой таблице.

$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.

Вот что еще я пробовал (я имею в виду неудачу)

Хорошо, давайте попробуем просто нацелить первую таблицу (добавив [0] до //th), посмотрим, сможем ли мы получить что-то.

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

Неа. Non-Object. Длина 0. Не уверен, почему. Хорошо, давайте снимем это.

Может быть, попробовать это?

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

Хорошо. Итак, длина = 100. Должно быть один th и экстраполяция. Не то, что я хочу.

Может быть, просто

//th[count(*)]

Неа. Non-объект.

Может быть, это?

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

Неа. Больше не-объектов.

Вероятно, достаточно примеров того, что я пробовал. Это было весело проваливать (и хорошо, учиться), но чего мне не хватает? Мой вывод ... Я просто хочу узнать, сколько <th> в каждой таблице.

Итак, вроде:

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 итераций.

Это, наверное, просто глупо. Я ссылался на этот шпаргалку , а также на этот шпаргалку , и я многое узнал о возможностях XPATH, но этот ответ намекает на меня. На данный момент я даже не уверен, что выполнение моего foreach ($intropath as $sp) { было даже правильным способом достижения того, что я делаю.

Кому-нибудь хочется выкопать меня из этой дыры, чтобы я мог перейти к следующему шагу и / или моей жизни?

Ответы [ 2 ]

0 голосов
/ 30 октября 2018

Подсчитайте квалифицирующие узлы, используя повторные вызовы query().

Код: ( Демо )

$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
0 голосов
/ 30 октября 2018

Сначала запросите table s:

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

Затем получите число th с для каждого table с помощью другого запроса XPath и функции PHP count, примененной ко всем th с относительно узла контекста:

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

Это должно быть все.

P.S:.
Очевидно, PHP не нравится функция XPath count, поэтому я использовал вместо нее функцию PHP count.


Просто для полноты:
Если вы можете использовать XPath-2.0, следующее выражение будет более компактным:

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

Здесь # - это разделитель между каждым числом table.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...