Re: [xsl] Grouping elements in xslt 1.0

Subject: Re: [xsl] Grouping elements in xslt 1.0
From: Martin Honnen <Martin.Honnen@xxxxxx>
Date: Tue, 01 Dec 2009 13:02:11 +0100
lee qm wrote:

Input xml (simplified version):

<?xml version="1.0" encoding="utf-8"?>
<ASBMessage id="id" version="version" timestamp="timestamp">
  <Body items="items">
     <AccountData operation="operation">
        <Account>
           <ID value="value" namespace="namespace"/>
           <ID value="value" namespace="namespace"/>
           <Type id="id"/>
        </Account>
     </AccountData>
  </Body>
</ASBMessage>


Expected output:


<?xml version="1.0" encoding="utf-8"?>
<data>
  <o t="TVEQE_ASBMessage">
     <a n="id">
        <v s="id"/>
     </a>
     <a n="timestamp">
        <v s="timestamp"/>
     </a>
     <a n="version">
        <v s="version"/>
     </a>
     <a n="TVEQE_Body">
        <o t="TVEQE_Body">
           <a n="items">
              <v s="items"/>
           </a>
           <a n="TVEQE_AccountData">
              <o t="TVEQE_AccountData">
                 <a n="operation">
                    <v s="operation"/>
                 </a>
                 <a n="TVEQE_Account">
                    <o t="TVEQE_Account">
                       <a n="TVEQE_ID">
                          <o t="TVEQE_ID">
                             <a n="namespace">
                                <v s="namespace"/>
                             </a>
                             <a n="value">
                                <v s="value"/>
                             </a>
                          </o>
                          <o t="TVEQE_ID">
                             <a n="namespace">
                                <v s="namespace"/>
                             </a>
                             <a n="value">
                                <v s="value"/>
                             </a>
                          </o>
                       </a>
                       <a n="TVEQE_Type">
                          <o t="TVEQE_Type">
                             <a n="id">
                                <v s="id"/>
                             </a>
                          </o>
                       </a>
                    </o>
                 </a>
              </o>
           </a>
        </o>
     </a>
  </o>
</data>

The stylesheet below groups child elements by the generated id of the parent element and by the qualified name of the child; that way it creates the output you have shown above.


<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  version="1.0">

<xsl:output indent="yes"/>

<xsl:key name="k1" match="*" use="concat(generate-id(..), '{', namespace-uri(), '}', local-name())"/>

  <xsl:template match="/ASBMessage">
    <data>
      <o t="TVEQE_{name(.)}">
        <xsl:apply-templates select="@* | *"/>
      </o>
    </data>
  </xsl:template>

  <xsl:template match="@*">
    <a n="{name(.)}"><v s="{.}"></v></a>
  </xsl:template>

<xsl:template match="*">
<a n="TVEQE_{name(.)}">
<xsl:for-each select="key('k1', concat(generate-id(..), '{', namespace-uri(), '}', local-name()))">
<o t="TVEQE_{name(.)}">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*[generate-id() = generate-id(key('k1', concat(generate-id(..), '{', namespace-uri(), '}', local-name()))[1])]"/>
</o>
</xsl:for-each>
</a>
</xsl:template>


</xsl:stylesheet>

--

	Martin Honnen
	http://msmvps.com/blogs/martin_honnen/

Current Thread