HTML — PHP DOM Parser — получить все узлы между двумя известными XPath

Как выбрать все DOM-узлы между двумя известными XPath?

Xpath1 = html/body/div[2]/p
Xpath2 = html/body/div[2]/p/a[3]

Структура DOM:

<html>
<body>
<div id="id3">
<p id="p3">
text1
<a href="#">
goal
</a>
text2
<a href="#">
Crowdrise
</a>.
</p>
</div>
</body>
</html>

Parser:

$dom = new DOMDocument();
$dom->loadHTML($domain);

$x = new DOMXPath($dom);
$el = $x->query("....??");

Итак, в основном ищем метод запроса для выбора всех узлов между двумя XPath.
Я видел пару подобных вопросов, однако они, похоже, относятся к случаям XSLT.

2

Решение

Хороший вопрос
Нет общего способа сделать это, потому что это зависит от положения второго элемента относительно первого. Я имею в виду, что если второй элемент является потомком первого или находится в другой ветви — эти два элемента совершенно разные.
поэтому нам нужно сделать предположение:

  • Давайте предположим, что второй элемент, определенный вторым путем, всегда будет потомком первого элемента, определенного первым путем.

Нашей целью будет получить все элементы-потомки (без текстовых узлов) первого элемента без общего потомка второго.

Для этого нам нужно выражение:

el1 = All element 1 descendants.
el2 = All element 2 descendants including self.
result = el1 [position() <= count( el1 ) - count( el2 )]

Как видите, мы строим набор из первых N элементов, пока не достигнем второго элемента.

Вот пример:

<?php

$dom = new DOMDocument();
$dom->loadHTML('<html>'
. '         <body>'
. '             <div>'
. '                 <h1>shlomi</h1>'
. '                 <p>'
. '                     <span>goal1</span>'
. '                     text1'
. '                     <a href="#">goal2</a>'
. '                     text2'
. '                     <a href="#"><span></span>Crowdrise</a>'
. '                     .'
. '                 </p>'
. '             </div>'
. '         </body>'
. '     </html>');

$x = new DOMXPath($dom);

$path1 = "/html/body/div/p/descendant::*";               // all descendant elements without text
$path2 = "/html/body/div/p/a[2]/descendant-or-self::*";  // all descendant elements without text including self
$path3 = $path1."[position() <= count(".$path1.") - count(".$path2.")]";
$elList = $x->query($path3);

foreach ($elList as $node) {
echo $node->nodeName." -> text: ".$node->textContent."<br />";
}

это напечатает:

span -> text: goal1
a    -> text: goal2

Заметка я использую * нацеливаться только на элементы без текстовых узлов — если вы хотите, чтобы все узлы заменили его на node(),

1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector