tags:

views:

67

answers:

1

I need to iterate through the alphabet a-z, and for each one, print the letter, and then place some code that i already have working to display all items in my database that begin with that letter. Currently, i'm using a select to retrieve the first letter of all the item names which i display. However, the requirement is to display all letters, and then show 'no items to display' where there are no items. So, i can no longer use my select, which only returns the letters that have items.

How can I do this, without hardcoding each letter, and then calling my template 26 times after each one?

+2  A: 

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my" >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:key name="kItemBy1stLetter" match="item"
  use="substring(.,1,1)"/>

 <xsl:variable name="vDoc" select="/"/>

 <xsl:variable name="vAlphabet" select=
 "'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"
 />

 <my:message>No items found.</my:message>

 <xsl:variable name="vMessage" select="document('')/*/my:message"/>

 <xsl:template match="/">
   <xsl:for-each select=
     "(document('')//node()|document('')//@*|document('')//namespace::*)
                          [ not(position() > 26)]
     ">

     <xsl:variable name="vcurLetter" select=
       "substring($vAlphabet, position(), 1)"/>
     <xsl:for-each select="$vDoc">
       <xsl:variable name="vSearchResult" select=
        "key('kItemBy1stLetter', $vcurLetter)"/>

       <xsl:value-of select="concat('&#xA;',$vcurLetter, ': &#xA;')"/>

       <xsl:copy-of select="$vSearchResult | $vMessage[not($vSearchResult)]/text()"/>
      </xsl:for-each>
      <xsl:text>&#xA;</xsl:text>
   </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

when applied on this XML document (playing the role of "database"):

<database>
 <item>Bicycles</item>
 <item>Computers</item>
 <item>Cars</item>
 <item>Forks</item>
 <item>Gellato</item>
 <item>Hypervehicles</item>
 <item>Ichtiosaurs</item>
 <item>Jobs</item>
 <item>Knots</item>
 <item>Lens</item>
 <item>Miracles</item>
 <item>Notes</item>
</database>

produces the wanted result:

A: 
No items found.

B: 
<item>Bicycles</item>

C: 
<item>Computers</item>
<item>Cars</item>

D: 
No items found.

E: 
No items found.

F: 
<item>Forks</item>

G: 
<item>Gellato</item>

H: 
<item>Hypervehicles</item>

I: 
<item>Ichtiosaurs</item>

J: 
<item>Jobs</item>

K: 
<item>Knots</item>

L: 
<item>Lens</item>

M: 
<item>Miracles</item>

N: 
<item>Notes</item>

O: 
No items found.

P: 
No items found.

Q: 
No items found.

R: 
No items found.

S: 
No items found.

T: 
No items found.

U: 
No items found.

V: 
No items found.

W: 
No items found.

X: 
No items found.

Y: 
No items found.

Z: 
No items found.
Dimitre Novatchev
@Dimitre: Good answer! And +1 for "you-will-go-to-hell-if-you-use-it" fixed iteration pattern. But, the alphabet is just there. So, I think it's a good thing to point out that there is nothing wrong in "calling my template 26 times after each one" with recursion.
Alejandro