Как вы найдете все узлы между двумя H3, используя XPATH?
Как вы найдете все узлы между двумя H3, используя XPATH?
Ответ 1
В XPath 1.0 одним из способов сделать это является использование метода Kayessian для node -set пересечения:
$ns1[count(.|$ns2) = count($ns2)]
Вышеприведенное выражение выбирает точно узлы, которые являются частью как node -set $ns1
, так и node -set $ns2
.
Чтобы применить это к конкретному вопросу - скажем, нам нужно выбрать все узлы между вторым и третьим элементами h3
в следующем XML-документе:
<html>
<h3>Title T31</h3>
<a31/>
<b31/>
<h3>Title T32</h3>
<a32/>
<b32/>
<h3>Title T33</h3>
<a33/>
<b33/>
<h3>Title T34</h3>
<a34/>
<b34/>
<h3>Title T35</h3>
</html>
Мы должны заменить $ns1
на:
/*/h3[2]/following-sibling::node()
и заменить $ns2
на:
/*/h3[3]/preceding-sibling::node()
Таким образом, полное выражение XPath:
/*/h3[2]/following-sibling::node()
[count(.|/*/h3[3]/preceding-sibling::node())
=
count(/*/h3[3]/preceding-sibling::node())
]
Мы можем проверить, что это правильное выражение XPath:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select=
"/*/h3[2]/following-sibling::node()
[count(.|/*/h3[3]/preceding-sibling::node())
=
count(/*/h3[3]/preceding-sibling::node())
]
"/>
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется к XML-документу, представленному выше, желаемый, правильный результат получается:
<a32/>
<b32/>
II. Решение XPath 2.0:
Используйте оператор intersect
:
/*/h3[2]/following-sibling::node()
intersect
/*/h3[3]/preceding-sibling::node()
Ответ 2
Другое решение XPath 1.0, когда вы знаете обе метки, - это один и тот же элемент (этот случай h3
):
/html/body/h3[2]/following-sibling::node()
[not(self::h3)]
[count(preceding-sibling::h3)=2]
Ответ 3
Более общее решение - в XPath 2.0 - при условии, что вам нужны узлы на всех глубинах дерева между двумя элементами h3, которые не обязательно будут братьями и сестрами.
/path/to/first/h3/following::node()[. << /path/to/second/h3]
Ответ 4
Основываясь на dimitre-novatchev отличный ответ, я могу ответить на следующее решение, которое вместо жесткого кодирования [2] и [3] для разных H3s я просто даю содержимое заголовка первого элемента.
//h3[text()="Main Page Section Heading"]/following-sibling::node()
[ count(.|//h3[text()="Main Page Section Heading"]/following-sibling::h3[1]/preceding-sibling::node()) =
count(//h3[text()="Main Page Section Heading"]/following-sibling::h3[1]/preceding-sibling::node()) ]
Где бы я хотел пойти дальше, хотя должен иметь дело со сценарием, когда я смотрю на последний H3, и получаю все после него, в приведенном выше случае я не могу получить то, что следует за последним H3.
Ответ 5
Существует еще одно большое общее решение, использующее ключи, предполагая, что теги <h3>
имеют уникальное свойство (например, его текст или атрибут id
):
<xsl:key name="siblings_of_h3" match="*[not(self::h3)]" use="preceding-sibling::h3[1]/text()"/>
<xsl:template match="h3">
<!-- now select all tags belonging to the current h3 -->
<xsl:apply-templates select="key('siblings_of_h3', text())"/>
</xsl:template>
Он группирует все теги по предыдущим <h3>