Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Ordering subsets within a nodeset

Status
Not open for further replies.

jd323

Technical User
Sep 1, 2005
7
0
0
GB
I have a source document with a structure which is basically like this:
<data>
<fruits>
<orange>orangeinfo</orange>
<apple>appleinfo</apple>
<apple>appleinfo</apple>
<orange>orangeinfo</orange>
<pear>pearinfo</pear>
</fruits>
</data>

* The document order is not necessarily the same as the output order.
* The output order requires each fruit type to be grouped together, and each of these subsets to be output in a particular order (let's say pears then apples then oranges).
* It is not necessary that any one fruit type is represented at all in the data (i.e. could be just apples and pears).
* The output is formatted like in this style: (pearinfo, appleinfo, appleinfo, orangeinfo, orangeinfo)


1) In my first attempt I asked questions of each node() as I go through a for-each loop, add the relevant seperators and paste in the value-of. This constructs the ( , , , ) structure correctly, but does not group the data at all. Altering the order in the for-each select expression does not affect the way the nodeset is created (document order). Thus the output is in document order:

<code>
<xsl:for-each select="orange | apple | pear">
<xsl:choose>
<xsl:when test="position()=1 and position()=last()">
<xsl:text> (</xsl:text>
<xsl:value-of select="."/>
<xsl:text>)</xsl:text>
</xsl:when>
<xsl:when test="position()=1">
<xsl:text> (</xsl:text>
<xsl:value-of select="."/>
<xsl:text>, </xsl:text>
</xsl:when>
<xsl:when test="position()=last()">
<xsl:value-of select="."/>
<xsl:text>)</xsl:text>
</xsl:when>
<xsl:eek:therwise>
<xsl:value-of select="."/>
<xsl:text>, </xsl:text>
</xsl:eek:therwise>
</xsl:choose>
</xsl:for-each>
</code>

2) My second approach was to use an apply-templates code. This groups the fruits together, but I do not keep track of where I am within the nodeset and in this case it leaves me with an undesired comma after the final orange, before the closing paranthesis. Essentially I cannot distinguish my first and final fruits for special treatment because I do not know what type of fruit they may be:

<code>
<xsl:template match="fruits">
<xsl:text> (</xsl:text>
<xsl:apply-templates select="pears"/>
<xsl:apply-templates select="apples"/>
<xsl:apply-templates select="oranges"/>
<xsl:text>) </xsl:text>
</xsl:template>
<xsl:template match="*">
<xsl:value-of select="."/>
<xsl:text>, </xsl:text>
</xsl:template>
</code>

Can anyone help with this problem? A solution using either approach is satisfactory, or a totally different approach if there is one and/or it is necessary.

Thanks
 
The easiest way would probably be to use a variable:
Code:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
  <xsl:output method="text" omit-xml-declaration="yes"/>
  <xsl:template match="/">
    <xsl:variable name="fruits"><xsl:apply-templates select="data/fruits"/></xsl:variable>
    <xsl:value-of select="concat('(', substring($fruits, 1, string-length($fruits) - 1), ')')"/>
  </xsl:template>
  <xsl:template match="fruits">
    <xsl:apply-templates select="pear"/>
    <xsl:apply-templates select="apple"/>
    <xsl:apply-templates select="orange"/>
  </xsl:template>
  <xsl:template match="node()">
    <xsl:value-of select="concat(., ',')"/>
  </xsl:template>
</xsl:stylesheet>

Jon

"I don't regret this, but I both rue and lament it.
 
Thankyou. The use of the substring fuction to clip the comma off the end is just what I was after. :)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top