Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Select child nodes based on their contents

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>
like image 484
krasnaya Avatar asked Apr 05 '09 07:04

krasnaya


People also ask

How do you specify a child element using XPath?

Accepted Answer. For the div element with an id attribute of hero //div[@id='hero'] , these XPath expression will select elements as follows: //div[@id='hero']/* will select all of its children elements. //div[@id='hero']/img will select all of its children img elements.

What is child :: In XPath?

The child axis indicates the children of the context node. If an XPath expression does not specify an axis, the child axis is understood by default. Since only the root node or element nodes have children, any other use will select nothing.

How do you get a child NodeList?

To get all child nodes of an element, you can use the childNodes property. This property returns a collection of a node's child nodes, as a NodeList object. By default, the nodes in the collection are sorted by their appearance in the source code. You can use a numerical index (start from 0) to access individual nodes.

What does childNodes return?

childNodes returns nodes: Element nodes, text nodes, and comment nodes. Whitespace between elements are also text nodes.


1 Answers

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']
like image 170
Dimitre Novatchev Avatar answered Sep 20 '22 16:09

Dimitre Novatchev