Выберите дочерние узлы на основе их содержимого

XML-фрагмент:

<AA>
  <BB>foo</BB>
  <CC>bar</CC>
  <DD>baz</DD>
  <EE>bar</EE>
</AA>

Как выбрать все дочерние узлы <AA>, у которых bar есть его содержимое? В приведенном выше примере я хотел бы выбрать <CC> и <EE>. Я думаю, что решение - это что-то вроде:

<xsl:template match="AA">
  <xsl:for-each select="???" />
</xsl:template>

Ответы

Ответ 1

Одним из простейших решений вопроса OP является следующее выражение XPath:

*/*[.='bar']

Обратите внимание, что никакая инструкция XSLT не задействована - это просто выражение XPath, поэтому вопрос может быть отмечен только с помощью XPath.

Здесь можно использовать это выражение XPath в XSLT различными способами, например, применять шаблоны для всех выбранных узлов.

Например, ниже представлено преобразование XSLT, которое принимает XML-документ и создает другой, в котором все элементы - дочерние элементы <AA>, содержимое которых не равно "bar", удаляются:

<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="node()|@*">
      <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
    </xsl:template>

    <xsl:template match="AA">
      <xsl:copy>
         <xsl:apply-templates select="*[. = 'bar']"/>
      </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Когда это преобразование применяется к исходному XML-документу:

<AA>
    <BB>foo</BB>
    <CC>bar</CC>
    <DD>baz</DD>
    <EE>bar</EE>
</AA>

получен желаемый результат:

<AA>
   <CC>bar</CC>
   <EE>bar</EE>
</AA>

Обратите внимание:

В шаблоне соответствия нам обычно не нужно указывать абсолютное выражение XPath, а просто относительное, поэтому полное выражение XPath, естественно, упрощается для этого шаблона соответствия:

*[. = 'bar']