[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

[xsl] Flat XML to nested XML by grouping


Subject: [xsl] Flat XML to nested XML by grouping
From: "Heiko Niemann" <kontakt@xxxxxxxxxxxxxxxx>
Date: Fri, 14 Mar 2014 01:39:40 +0100

Hi,

I want to transform a flat XML document to a XML document with nested
elements. Basically I have a solution for my case. But I would like to
know whether it is a good (the 'right') approach, since grouping sometimes
still gets my brain twisted.

Source:

<flat>
  <A/>
  <B/>
  <C/>
  <D/>
  <E/>
  <F/>
  <G/>
  <D/>
  <E/>
  <F/>
  <G/>
  <H/>
  <I/>
</flat>


Desired output:

<structured>
  <A/>
  <B/>
  <C/>
  <D>
    <E>
      <F/>
      <G/>
    </E>
  </D>
  <D>
    <E>
      <F/>
      <G/>
    </E>
  </D>
  <H/>
  <I/>
</structured>


Stylesheet:

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

  <xsl:template match="/flat">
    <structured>
      <xsl:for-each-group select="*" group-starting-with="A|B|C|D|H|I">
        <xsl:apply-templates select="."/>
      </xsl:for-each-group>
    </structured>
  </xsl:template>

  <xsl:template match="*">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="D">
    <xsl:copy>
      <xsl:for-each-group select="current-group() except ."
group-starting-with="E">
        <xsl:apply-templates select="."/>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="E">
    <xsl:copy>
      <xsl:apply-templates select="current-group() except ."/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>


I found some samples for transformations of this kind, but the output XML
usually had the format 'tree-without-tail' whereas in my sample the tree
has a tail: elements H and I. I hope you get the picture. :) So my
solution right now puts all elements that are supposed to be on first
level into the first group-starting-with-pattern. If there had not been a
'tail' I probably would just have said group-starting-with="D" (with
elements A,B,C in the first group).
I also wondered whether for this task it would be a good idea to have a
template for each element of the input XML, so one would be more flexible
and be sure not missing a case? (I am aware that in my sample nothing than
copying takes place, but in case I wanted to do more complex operations.)
Would that be a general approach? I recall a post on this list where
somebody mentioned that whenever he starts a stylesheet he would create
templates for each element appearing in the source document.

Thanks for comments and suggestions.

Regards,
Heiko


Current Thread
Keywords
xml