Yossi Dahan [BizTalk]

Google
 

Wednesday, August 02, 2006

Grouping in xslt

One of the 3rd parties we're connection to in our solution uses xml in a quite non-standard way, this constantly adds complexity to our solution. On the up side it does keep things interesting and sharpens our xsl skills!

The latest quirk is when we get an xml that can be represented like this -

<a>
<b/>
<b/>
<c>c1</c>
<d>d1</d>
<b/>
<e>e2</e>
<c>c2</c>
<b/>
<f>f3</f>
<b/>
</a>

You may spot that element b repeats itself several times with elements c, d and e in between. The logic is that all the elements between one b element to another are really children of the former b.

So - this xml should really look like -

<a>
<b/>
<b>
<c>c1</c>
<d>d1</d>
</b>
<b>
<e>e2</e>
<c>c2</c>
</b>
<b>
<f>f3</f>
</b>
<b/>
</a>

The xsl to get from one to the other -

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/a">
<a>
<xsl:for-each select="b">
<b>
<xsl:variable name="thisB" select="generate-id(current())"/>
<xsl:for-each select="following-sibling::*[name()!='b' and generate-id(preceding-sibling::b[1]) = $thisB]">
<xsl:variable name="nextB" select="generate-id(preceding-sibling::b[1])"/>
<xsl:element name="{name()}">
<xsl:value-of select="current()"/>
</xsl:element>
</xsl:for-each>
</b>
</xsl:for-each>
</a>
</xsl:template>
</xsl:stylesheet>

The idea is to loop on each b element, for each one use the generate-id function to generate a unique id and then loop on all the following siblings of the current b node until you get to another b node with a generated id that is different from the current one.

0 Comments:

Post a Comment

<< Home