Re: [xsl] Add a level of structure?

Subject: Re: [xsl] Add a level of structure?
From: George Cristian Bina <george@xxxxxxx>
Date: Mon, 20 Jun 2005 09:32:35 +0300
Hi Edmund,

You can use something like below:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="a">
<foo>
<xsl:apply-templates/>
</foo>
</xsl:template>
<xsl:template match="b">
<bar>
<xsl:variable name="sortedCs">
<xsl:for-each select="c">
<xsl:sort select="c1" data-type="number"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$sortedCs/*">
<xsl:if test="position() mod 3 =1">
<baz>
<xsl:call-template name="specificContent">
<xsl:with-param name="pos" select="(position()-1) div 3"/>
</xsl:call-template>
<xsl:apply-templates select="."/>
<xsl:apply-templates select="following-sibling::c[1]"/>
<xsl:apply-templates select="following-sibling::c[2]"/>
</baz>
</xsl:if>
</xsl:for-each>
</bar>
</xsl:template>
<xsl:template name="specificContent">
<xsl:param name="pos"/>
<xsl:choose>
<xsl:when test="$pos=0">
<x att="val" att2="val2"/>
<y att="val" att2="val2"/>
</xsl:when>
<xsl:when test="$pos=1">
<q att="val" att2="val2"/>
<r att="val" att2="val2"/>
</xsl:when>
<xsl:otherwise>
<g att="val" att2="val2"/>
<h att="val" att2="val2"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="c">
<c>
<xsl:value-of select="c1"/>
</c>
</xsl:template>
</xsl:stylesheet>


This is XSLT 2.0, for 1.0 you need exsl:node-set, that is add xmlns:exslt="http://exslt.org/common"; and change the for-each to read:
<xsl:for-each select="exslt:node-set($sortedCs)/*">


Best Regards,
George
---------------------------------------------------------------------
George Cristian Bina
<oXygen/> XML Editor, Schema Editor and XSLT Editor/Debugger
http://www.oxygenxml.com


Edmund Mitchell wrote:
Hello all,

Source xml looks like this, can have between 0-9 c's:

<a>
<b>
<c>
<c1>9</c1>
<c2/>
</c>
<c>
<c1>33</c1>
<c2/>
</c>
<c>
<c1>1</c1>
<c2/>
</c>
<c>
<c1>3</c1>
<c2/>
</c>
<c>
<c1>16</c1>
<c2/>
</c>
<c>
<c1>50</c1>
<c2/>
</c>
</b>
</a>
I need to first sort all the c's based on the value of their c1 child (a
number, and the child always exists with the parent), then, for each three
c's, put them inside another element, which also contains some hard-coded
information that is dependent on the c group. Lastly, there will always be
3 groups, even if there aren't enough c's to justify the group's existence.


So the result needs to look something like:

<foo>
	<bar>
		<baz>
			<!-- since this is the first baz group, add some
first-group specific stuff -->
			<x att="val" att2="val2"/>
			<y att="val" att2="val2"/>
			<!-- now the first three c's whose c1 child had the
lowest value, in this case 1, 3, and 9 -->
			<c> <!-- some stuff based on the c whose c1 child
was 1 --></c>
			<c> <!-- some stuff based on the c whose c1 child
was 3 --></c>
			<c> <!-- some stuff based on the c whose c1 child
was 9 --></c>
		</baz>
		<baz>
			<!-- since this is the 2nd baz group, add some
2nd-group specific stuff -->
			<q att="val" att2="val2"/>
			<r att="val" att2="val2"/>
			<!-- now the first three c's whose c1 child had the
next-lowest value, in this case 16, 33 and 50 -->
			<c> <!-- some stuff based on the c whose c1 child
was 16 --></c>
			<c> <!-- some stuff based on the c whose c1 child
was 33 --></c>
			<c> <!-- some stuff based on the c whose c1 child
was 50 --></c>
		</baz>
		<baz>
			<!-- since this is the 3rd baz group, add some
third-group specific stuff -->
			<g att="val" att2="val2"/>
			<h att="val" att2="val2"/>
			<!-- nothing here, but the group, and the hard-coded
stuff must appear -->
			<!-- if there was another 1-3 c's, they'd be in this
group -->
		</baz>
	</bar>
</foo>

I've been for-each-ing and postion()-ing myself to death all day; it's time
to ask the Masters.

Thanks for any help

E

Current Thread