Subject: Re: multiple output and grouping From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx> Date: Thu, 16 Nov 2000 10:27:52 +0000 |
Luca, > That is, I have a list of authors and a list of records associated > with each author. What I want to do is sorting the list by author > and grouping the authors (with their records) alphabetically in > different HTML files, like this: OK. First you need to be able to, given a letter, find out which authors to output. You can find the authors whose names begin with a certain letter using starts-with(). For example: /authors/author[starts-with(name, $letter)] In other words, select the author elements whose name child element starts with $letter. Or you can set up a key that lets you index into the list of authors according to the first letter of their name: <xsl:key name="authors" match="author" use="substring(name, 1, 1)" /> In other words, set up a key space called 'authors' that indexes into any author elements according to the first character of their name. You can then access all authors whose names start with a certain letter using: key('authors', $letter) This is probably more efficient, especially as you'll be retrieving them 26 times, and especially if you have a long list of authors (as I guess is likely?) So, given a letter, you can collect the nodes that represent the authors together and output whatever you want from them. When you iterate over them using xsl:for-each or apply templates to then using xsl:apply-templates you can sort them according to their name using xsl:sort: <xsl:sort select="name" /> You need to have the letter passed into this general template as a parameter. Something like: <xsl:template name="output-authors-by-letter"> <xsl:param name="letter" select="'A'" /> <saxon:output file="{$letter}.html"> <html> <head> <title>Authors starting with <xsl:value-of select="$letter" /></title> </head> <body> <h1><xsl:value-of select="$letter" /></h1> <xsl:for-each select="key('authors', $letter)"> <xsl:sort select="name" /> <h2><xsl:value-of select="name" /></h2> <xsl:apply-templates select="records" /> </xsl:for-each> </body> </html> </saxon:output> </xsl:template> So, how to get the letter to be passed into the template. First, you need to know your alphabet, so set a variable up to hold it: <xsl:variable name="alphabet" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" /> Now you need something to work its way through that string. In XSLT you can do this by recursion: have a template that takes a string (starting with the full alphabet), takes the first letter and calls the above template with it, and then calls itself on the rest of that string: <xsl:template name="output-authors"> <xsl:param name="alphabet" select="$alphabet" /> <xsl:if test="$alphabet"> <xsl:call-template name="output-authors-by-letter"> <xsl:with-param name="letter" select="substring($alphabet, 1, 1)" /> </xsl:call-template> <xsl:call-template name="output-authors"> <xsl:with-param name="alphabet" select="substring($alphabet, 2)" /> </xsl:call-template> </xsl:if> </xsl:template> You can also do this using xsl:for-each and the Piez Technique (see, Wendell ;) Take a node set of 26 nodes (you probably have that many elements in your document easily) and iterate over them, using the position() of the node to tell which letter to take from the alphabet: <xsl:template name="output-authors"> <xsl:for-each select="//*[position() <= 26]"> <xsl:call-template name="output-authors-by-letter"> <xsl:with-param name="letter" select="substring($alphabet, position(), 1)" /> </xsl:call-template> </xsl:for-each> </xsl:template> I hope that helps, Jeni --- Jeni Tennison http://www.jenitennison.com/ XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
multiple output and grouping, Luca | Thread | RE: multiple output and grouping, Kay Michael |
RE: multiple output and grouping, Kay Michael | Date | Re: Node set comnparison, Jeni Tennison |
Month |