Как выбрать все 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.
Хороший вопрос
Нет общего способа сделать это, потому что это зависит от положения второго элемента относительно первого. Я имею в виду, что если второй элемент является потомком первого или находится в другой ветви — эти два элемента совершенно разные.
поэтому нам нужно сделать предположение:
Нашей целью будет получить все элементы-потомки (без текстовых узлов) первого элемента без общего потомка второго.
Для этого нам нужно выражение:
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()
,
Других решений пока нет …