Thursday, June 14, 2007

Annotated XSLT - Numbering and Grouping

If you are trying to figure out xsl you should really be reading the very active xsl list. Subscribe or search the archive.

Knowledgeable members of the XSL mailing list frequently post elegant solutions for problems other posters can't quite resolve. There's usually a short note that tells you what to look up to figure out how the solution works. This time Wendell Piez walks you through David Carlisle's numbering and grouping solution line by line. He explains what each line or grouping is doing, what it's acting on, and what the result will be. To read the thread in the archive, click here.

From the post:

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&quot;>

<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[.&lt;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

Sunday, June 03, 2007

New Way to Support Side Stories That Are Not Supported By Publishers Of Popular Series

Seems to be hard for writers to get their publishers to put out books that are not core to a popular series. Sharon Lee and Steve Miller are doing it themselves over the internet.

This isn't entirely new. I know people who regularly support a number of web comics where the demand exceeded the artist's ability to produce in their spare time. The artist, having thrown up their hands in frustration at the brash demands and complaints, said effectively, "Here's a Pay Pal account. Put up or shut up." I would have loved to have seen the look on the face of the fist poor guy who suddenly found himself with enough money to quit the day job.

So back to the writers, who have a slightly different animal to manage and who have found a way to get the job done. There's a "change of rules" notice on the page so I'm not sure what was there to begin with but it looks like they said effectivley:
  • We've got a story.
  • It won't get published unless there's interest ahead of time.
  • Here's a Pay Pal account.
  • We'll publish first draft chapters, on a regular shedule as long as there's money to cover the cost.
  • If we get to minimum publishing amount we'll get it out in trade paperback.
  • If you donate more than a certain amount, you will get yours free."
Looks like they made it. Cool.

Draft chapters are available up to chapter 16, so far.

You can read about the approach and the chapters here: