Search code examples
xmlxsltforeachvalue-of

Parsing XML with child elements that have the same name using XSLT/XSL


I am wondering if there is a way to transfer over a parent element with all of its children elements that have the same element name using XSLT.

For example, if the original xml file is like this:

<parent>
  <child>1</child>
  <child>2</child>
  <child>3</child>
</parent>

And I try to parse it with xsl using:

<xsl:for-each select="parent">
  <print><xsl:value-of select="child"></print>

wanting something like this:

<print>1</print>
<print>2</print>
<print>3</print>

but I get this:

<print>1</print>

because the for-each is more designed for this format:

<parent>
  <child>1</child>
<parent>
</parent
  <child>2</child>
<parent>
</parent
  <child>3</child>
</parent

Is there anyway to get the desired printout without formatting it like it is above, but rather the first way?

Thanks


Solution

  • It's because you're doing the xsl:for-each on the parent instead of the child. You would get the results you're looking for if you changed it to this (assuming the current context is /):

    <xsl:for-each select="parent/child">
      <print><xsl:value-of select="."/></print>
    </xsl:for-each>
    

    However... using xsl:for-each is usually not necessary. You should let overriding templates handle the work for you instead of trying to get to all of the children from a single template/context (like /)

    Here's a complete stylesheet for an example:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output indent="yes"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:template match="node()|@*">
        <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="parent">
        <xsl:apply-templates/>
      </xsl:template>
    
      <xsl:template match="child">
          <print><xsl:apply-templates/></print>
      </xsl:template>
    
    </xsl:stylesheet>
    

    the output of this stylesheet would be:

    <print>1</print>
    <print>2</print>
    <print>3</print>