Ответ 1
Что-то другое::)
//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1]
Кажется намного короче других решений, не так ли?:)
Переведен на простой английский. Для любого текста node в документе, который содержит строку "abc"
, выберите своего первого предка, который является либо div
, либо table
.
Это более эффективно, так как требуется только одно полное сканирование дерева документа (а не любое другое), а обход ancestor::*
очень дешев по сравнению с descendent::
(дерево).
Чтобы убедиться, что это решение действительно работает:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:copy-of select=
"//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1] "/>
</xsl:template>
</xsl:stylesheet>
, когда это преобразование выполняется на предоставленном XML-документе:
<div>
<table>
<form>
<div>
<span>
<p>abcdefg</p>
</span>
</div>
<table>
<span>
<p>123456</p>
</span>
</table>
</form>
</table>
</div>
требуется, правильный результат получается:
<div>
<span>
<p>abcdefg</p>
</span>
</div>
Примечание. Нет необходимости использовать XSLT - любой хост XPath 1.0, такой как DOM, должен получить тот же результат.