Moving XSLT from flat to nested

I can't seem to handle simple (?) XSLT Transformation.

There is an input flat structured XML:

<root>
    <attribute_a>abc</attribute_a>
    <attribute_b>def</attribute_b>
    <attribute_c>ghi</attribute_c>
    <attribute_a>123</attribute_a>
    <attribute_b>456</attribute_b>
    <attribute_c>789</attribute_c>
    <attribute_a>xxx</attribute_a>
    <attribute_b>xxx</attribute_b>
    <attribute_c>xxx</attribute_c>
</root>

      

I have to convert it to XML like this:

<root>
    <attribute>
        <attribute_a>abc</attribute_a>
        <attribute_b>def</attribute_b>
        <attribute_c>ghi</attribute_c>
    </attribute>
    <attribute>
        <attribute_a>123</attribute_a>
        <attribute_b>456</attribute_b>
        <attribute_c>789</attribute_c>
    </attribute>
    <attribute>
        <attribute_a>xxx</attribute_a>
        <attribute_b>xxx</attribute_b>
        <attribute_c>xxx</attribute_c>
    </attribute>
</root>

      

But the problem is the following conversion:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />

    <xsl:template match="/">
        <root>
            <xsl:for-each select="root/attribute_a">
                <attribute>
                    <attribute_a>
                        <xsl:value-of select="../attribute_a" />
                    </attribute_a>
                    <attribute_b>
                        <xsl:value-of select="../attribute_b" />
                    </attribute_b>
                    <attribute_c>
                        <xsl:value-of select="../attribute_c" />
                    </attribute_c>
                </attribute>
            </xsl:for-each>
        </root>
        <xsl:apply-templates />
    </xsl:template>
</xsl:stylesheet>

      

I have something like this:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <attribute>
        <attribute_a>abc</attribute_a>
        <attribute_b>def</attribute_b>
        <attribute_c>ghi</attribute_c>
    </attribute>
    <attribute>
        <attribute_a>abc</attribute_a>
        <attribute_b>def</attribute_b>
        <attribute_c>ghi</attribute_c>
    </attribute>
    <attribute>
        <attribute_a>abc</attribute_a>
        <attribute_b>def</attribute_b>
        <attribute_c>ghi</attribute_c>
    </attribute>
</root>

      

I'm not very good at XSLT - do you have any ideas ?:(

Best regards, AM

+3


source to share


1 answer


This should do the trick:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/">
    <root>
      <xsl:for-each select="root/attribute_a">
        <xsl:variable name="pos" select="position()"/>
        <attribute>
          <xsl:apply-templates
            select="../attribute_a[$pos] | 
                    ../attribute_b[$pos] |
                    ../attribute_c[$pos]" />
        </attribute>
      </xsl:for-each>
    </root>
  </xsl:template>
</xsl:stylesheet>

      

And I suggest taking it one step further and using a separate template instead for-each

:



<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/">
    <root>
      <xsl:apply-templates select="root/attribute_a" mode="group" />
    </root>
  </xsl:template>

  <xsl:template match="attribute_a" mode="group">
    <xsl:variable name="pos" select="position()"/>
    <attribute>
      <xsl:apply-templates
        select="../attribute_a[$pos] | ../attribute_b[$pos] | ../attribute_c[$pos]" />
    </attribute>
  </xsl:template>
</xsl:stylesheet>

      

When any of these XSLTs are run on your example input, it produces this output:

<root>
  <attribute>
    <attribute_a>abc</attribute_a>
    <attribute_b>def</attribute_b>
    <attribute_c>ghi</attribute_c>
  </attribute>
  <attribute>
    <attribute_a>123</attribute_a>
    <attribute_b>456</attribute_b>
    <attribute_c>789</attribute_c>
  </attribute>
  <attribute>
    <attribute_a>xxx</attribute_a>
    <attribute_b>xxx</attribute_b>
    <attribute_c>xxx</attribute_c>
  </attribute>
</root>

      

+1


source







All Articles