Question

XML snippet:

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

How do I select all the child nodes of <AA> that have bar as its contents? In the example above, I'd want to select <CC> and <EE>. I'm thinking the solution is something like:

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

Solution

One of the simplest solutions to the OP's question is the following XPath expression:

*/*[.='bar']

Do note, that no XSLT instruction is involved -- this is just an XPath expression, so the question could only be tagged XPath.

From here on, one could use this XPath expression in XSLT in various ways, such as to apply templates upon all selected nodes.

For example, below is an XSLT transformation that takes the XML document and produces another one, in which all elements - children of <AA> whose contents is not equal to "bar" are deleted:

<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>

When this transformation is applied on the original XML document:

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

the wanted result is produced:

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

Do note:

In a match pattern we typically do not need to specify an absolute XPath expression, but just a relative one, so the full XPath expression is naturally simplified to this match pattern:

*[. = 'bar']
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top