Good literature deserves commentary --
At 04:17 PM 5/25/2007, David wrote:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="g" match="group_id" use="." />
The 'g' key matches group-id elements by their value, so for example
key('g','250') returns all group-id elements with value '250'
(however many there are). This is the essence of a Muenchian group.
<xsl:output indent="yes"/>
For cosmetics.
<xsl:variable name="g"
select="/sample/result/details/group_id[generate-id()=generate-id(key('g',.))]"/>
This selects a set of elements, binding them to $g. The set is all
the group-id elements whose unique identifier (returned by
generate-id()) has the same value as the unique id of the first
element returned from the 'g' key using their value (following the
XSLT 1.0 rule that the generated id of a set of nodes will be that of
the first node in the set, in document order). That is, it returns
the first group-id element in the document that appears with any
given value -- so all values are returned exactly once.
You can call these "flag-bearer" elements if you like, since they
correspond exactly to the groups of group-id elements, using their values.
<xsl:template match="sample">
<xsl:for-each select="$g">
Iterating over the flag-bearers is equivalent to iterating over the
groups themselves (since each can be used to retrieve its group).
<xsl:sort select="."/>
Dr Carlisle sorts the groups' flag-bearers by their values, so the
groups will come out in ascending order by value.
<xsl:variable name="p" select="position()-1"/>
This returns us '0' for the first group, 'n-1' for the nth group, in
their sorted order.
<xsl:variable name="c" select="count(key('g',$g[.<current()]))"/>
This returns us the count of the members of all the groups that will
appear before this one (a tricky business), by finding all the
flag-bearers whose value is less than the current group's, collecting
all the members of their groups, and counting them. The key makes
this reasonably efficient to do -- but it wouldn't work if we weren't
outputting the groups ordered by their values (he'd have to come up
with something else).
<xsl:for-each select="key('g',.)">
Now we iterate over the members of the group belonging to this flag-bearer.
<output row="{$c+$p+position()}"><xsl:value-of select="."/></output>
We write an 'output' element. The value of its @row is calculated as:
* The count of all the members of the groups preceding this one
(since they'll appear above this one)
* The number of blank lines we'll also include, which happens to be $p
* The position of this member of the group within the group
Its value is its value.
</xsl:for-each>
We're done with the members of this group.
<xsl:if test="position()!=last()">
But unless we're the last group (or rather: the last flag-bearer), we
also want...
<output row="{$c+count(key('g',.))+$p+1}"/>
... a blank 'output' element whose row is calculated as the sum of
all the members of the groups preceding this one, all the members of
this group, the blank lines preceding this one, and 1 (for this blank line)
</xsl:if>
</xsl:for-each>
</xsl:template>
We're done.
Have a good weekend.
Cheers,
Wendell
======================================================================
Wendell Piez
mailto:wapiez(_at_)mulberrytech(_dot_)com
Mulberry Technologies, Inc. http://www.mulberrytech.com
17 West Jefferson Street Direct Phone: 301/315-9635
Suite 207 Phone: 301/315-9631
Rockville, MD 20850 Fax: 301/315-8285
----------------------------------------------------------------------
Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================
--~------------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--