Xpath: отфильтровывать дочерние элементы
Я ищу выражение xpath, которое отфильтровывает определенных потомков. Ребенок должен содержать узел CCC с буквой B.
Источник:
<AAA>
<BBB1>
<CCC>A</CCC>
</BBB1>
<BBB2>
<CCC>A</CCC>
</BBB2>
<BBB3>
<CCC>B</CCC>
</BBB3>
<BBB4>
<CCC>B</CCC>
</BBB4>
</AAA>
Это должно быть результатом:
<AAA>
<BBB3>
<CCC>B</CCC>
</BBB3>
<BBB4>
<CCC>B</CCC>
</BBB4>
</AAA>
Надеюсь, кто-нибудь может мне помочь.
Jos
4 ответа
XPath - это язык запросов для документов XML. Таким образом, он может выбирать только узлы из существующих документов XML - он не может изменять документ XML или создавать новый документ XML.
Используйте XSLT для преобразования XML-документа и создания нового XML-документа из него.
В этом конкретном случае:
<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="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*/*[not(CCC = 'B')]"/>
</xsl:stylesheet>
когда это преобразование применяется к предоставленному документу XML:
<AAA>
<BBB1>
<CCC>A</CCC>
</BBB1>
<BBB2>
<CCC>A</CCC>
</BBB2>
<BBB3>
<CCC>B</CCC>
</BBB3>
<BBB4>
<CCC>B</CCC>
</BBB4>
</AAA>
желаемый, правильный результат получается:
<AAA>
<BBB3>
<CCC>B</CCC>
</BBB3>
<BBB4>
<CCC>B</CCC>
</BBB4>
</AAA>
Чтобы выбрать все нужные элементы и текстовые узлы, используйте этот XPATH:
//node()[.//CCC[.='B']
or self::CCC[.='B']
or self::text()[parent::CCC[.='B']]]
Это может быть достигнуто с помощью более простого / легкого использования XPATH с измененным XSLT-преобразованием идентичности:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" />
<!--Empty template for the content we want to redact -->
<xsl:template match="*[CCC[not(.='B')]]" />
<!--By default, copy all content forward -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Попробуй это,
"//CCC[text() = 'B']"
Он должен дать все узлы CCC, где внутренний текст равен B.
Если вы хотите получить AAA, BBB3 и BBB4, вы можете использовать следующие
//*[descendant::CCC[text()='B']]
Если BBB3 и BBB4 только тогда
//*[CCC[text()='B']]