Re: [xsl] sort question

Hi Kim,
> I'm obviously missing something in reading through the sorting
> examples available on many web sites. All I want to do is obtain the
> same nodes out of the transformation, just sorted. Sort order is
> only applied to the KH and Key nodes, the KH nodes sort by the KSort
> attribute value and within a KH node, the Key nodes sort by the
> KeySort value. No other nodes require sorting, they should remain in
> the order they were in originally. I keep getting the same nodes in
> the same order they started with from the transformation, I am not
> getting a sort applied. Could someone enlighten me as to what I am
> missing?
You're *so* close. In your template:
> <xsl:template match="/">
> <xsl:apply-templates select="Data/KH">
> <xsl:sort select="@KSort" data-type="text" order="ascending"/>
> <xsl:sort select="Key[@KeySort]" data-type="text" order="ascending"/>
> </xsl:apply-templates>
> <xsl:copy-of select="node()"/>
> </xsl:template>
You apply templates to the KH elements in your Data. The order in
which you apply templates is determined by the two sorts; the primary
sort is on the KSort attribute of the KH element and the second sort
is on the value of the first Key element child of the KH element that
has a KeySort attribute.
Leaving aside whether that was what you wanted to sort on or not, the
main problem is that you are applying templates in this order, but
don't have a template to copy the nodes that you're applying templates
to! There aren't any templates that match the KH elements (the only
template in your stylesheet is the root-node-matching template above),
so the built-in templates are used. The built-in templates just give
you the string value of the relevant nodes - none of the KH elements
have a string value, so you don't get anything from them.
Then the last thing you do, after applying templates like this, is to
create a complete copy of the node children of the current node. The
current node in the template is the root node, so in effect you do a
complete copy of the document, giving you exactly what you put in.
So, the first thing to do is set up a default template that matches an
element and makes a copy of it and its attributes, then moves on
recursively, applying templates to its children:
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates select="node()" />
</xsl:copy>
</xsl:template>
Now, when you get down to the Data elements that hold KH elements as
children, you want to vary this slightly. Rather than simply applying
templates to the KH elements in order, you want to apply them in
sorted order. So add the sort that you've currently got in your
root-node-matching template to this one instead:
<xsl:template match="Data[KH]">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates select="KH">
<xsl:sort select="@KSort" />
<xsl:sort select="Key[@KeySort]" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
The KH elements will be collected together, sorted, and then have
templates applied to them. The KH elements will match the default
template above, and so be copied.
Now, about the sort. It sounds as if you actually want two levels of
sorting - within the Data element, you want the KH elements to be
sorted by the KSort attribute, and within the KH elements you want the
Key elements to be sorted by the KeySort value. So when a template is
applied to a KH element you actually want it to apply templates to its
children (the Key elements) in order:
<xsl:template match="KH">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates select="Key">
<xsl:sort select="@KeySort" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
It may be worth amending your Data-matching template to mirror this
change by taking out that second, spurious, sort:
<xsl:template match="Data[KH]">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates select="KH">
<xsl:sort select="@KSort" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
Having two xsl:sort elements is useful if, say, you had KH elements
that had the same value for their KSort attribute and wanted to sort
them according to their KHID or the number of Key elements they
contain or something. In other words, its for sorting the *same
things* as the primary sort, just on different values.
I hope that helps,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list