Вот то же самое решение :
Одно выражение XPath, которое выбирает именно нужные элементы, равно :
//*[set[. = 'erase' and not(node()[2])]
and
not(ancestor::*
[set
[. = 'erase' and not(node()[2])]
]
)
]
Проверка на основе XSLT :
<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:for-each select=
"//*[set[. = 'erase' and not(node()[2])]
and
not(ancestor::*
[set
[. = 'erase' and not(node()[2])]
]
)
]">
<xsl:value-of select="name()"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
, когда это преобразование применяется к предоставленному документу XML :
<a>
<b>
<set>erase</set>
<d>
<set>erase</set>
</d>
</b>
<c>
<x></x>
</c>
<e>
<y>
<set>erase</set>
<q></q>
</y>
<z>
<p>
<set>erase</set>
</p>
</z>
</e>
</a>
Содержимое выражения XPath оценивается, и имена выбранных элементов выводятся - правильно и как ожидалось :
b
y
p
Если вам нужно выбрать set
потомков из указанных вышеэлементы, просто добавьте приведенное выше выражение XPath с помощью /set
:
//*[set[. = 'erase' and not(node()[2])]
and
not(ancestor::*
[set
[. = 'erase' and not(node()[2])]
]
)
]
/set
Опять же, XSLT-проверка :
<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=
"//*[set[. = 'erase' and not(node()[2])]
and
not(ancestor::*
[set
[. = 'erase' and not(node()[2])]
]
)
]
/set
"/>
</xsl:template>
</xsl:stylesheet>
Это преобразование простооценивает приведенное выше выражение XPath и копирует на выход правильно выбранные три set
элемента :
<set>erase</set>
<set>erase</set>
<set>erase</set>