Запрос XPath с потомком и потомком текста () предикатов
-
29-09-2019 - |
Вопрос
Я хотел бы построить запрос XPath, который вернет элемент «div» или «таблица», пока у него есть потомк, содержащий текст «ABC». Одно оговорку состоит в том, что не может иметь никаких потомков Div или таблиц.
<div>
<table>
<form>
<div>
<span>
<p>abcdefg</p>
</span>
</div>
<table>
<span>
<p>123456</p>
</span>
</table>
</form>
</table>
</div>
Таким образом, единственный правильный результат этого запроса будет:
/div/table/form/div
Моя лучшая попытка выглядит что-то подобное:
//div[contains(//text(), "abc") and not(descendant::div or descendant::table)] | //table[contains(//text(), "abc") and not(descendant::div or descendant::table)]
Но не возвращает правильный результат.
Спасибо за вашу помощь.
Решение
Что-то другое: :)
//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1]
Кажется, намного короче, чем другие решения, не так ли? :)
Перевод на простой английский: Для любого текстового узла в документе, который содержит строку "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, должен получить тот же результат.
Другие советы
//*[self::div|self::table]
[descendant::text()[contains(.,"abc")]]
[not(descendant::div|descendant::table)]
Проблема с contains(//text(), "abc")
Это функции литых узлов наборы принимают первый узел.
Вы можете попробовать:
//div[
descendant::text()[contains(., "abc")]
and not(descendant::div or descendant::table)
] |
//table[
descendant::text()[contains(., "abc")]
and not(descendant::div or descendant::table)
]
Это помогает?