[xsl] Showing unique rows at multiple levels

Subject: [xsl] Showing unique rows at multiple levels
From: Glen Mazza <grm7790@xxxxxxxxxxx>
Date: Wed, 04 Oct 2006 14:07:44 -0400
Hello, for this input XML:

<books>
   <book>
       <title>T1</title>
       <author>A5</author>
       <publisher>P7</publisher>
       <bookshelf>B4</bookshelf>
   </book>
   <book>
       <title>T2</title>
       <author>A6</author>
       <publisher>P8</publisher>
       <bookshelf>B4</bookshelf>
   </book>
   <book>
       <title>T4</title>
       <author>A5</author>
       <publisher>P7</publisher>
       <bookshelf>B6</bookshelf>
   </book>
   <book>
       <title>T3</title>
       <author>A5</author>
       <publisher>P7</publisher>
       <bookshelf>B4</bookshelf>
   </book>
</books>

I would like an alphabetically sorted list of each unique bookshelf, and under each bookshelf, each unique author of at least one book on that shelf, and under each author, each unique publisher of at least one book by that author (on that shelf).

I.e., for the above, the following is desired:

B4
--A5   (show just once even though 2 books of A5)
----P7 (show just once even though 2 books of P7 under A5 on B4)
--A6
----P8
B6
--A5
----P7

Unfortunately, I am getting this:

B4
--A5
----P7
--A6
----P8
B6

where A5 and P7 are erroneously missing under shelf B6, because A5 and P7 already happen to exist under shelf B4. (In my sample data, if I rename A5 to say A15 and P7 to P17, i.e., nodes that don't exist elsewhere, these nodes then *will* appear under B6.)

Something is wrong with my filtering--I only want an author to be suppressed if it is already listed for the *same* shelf, and likewise with publishers under the same author (under the same shelf).

Here is my XSLT:

<xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

<xsl:template match="books">
   <xsl:for-each select="//bookshelf[not(.=preceding::bookshelf)]">
        <xsl:sort select="."/>
        <xsl:apply-templates select='.'/>
   </xsl:for-each>
</xsl:template>

<xsl:template match="bookshelf">
<xsl:variable name="bookshelfVar" select="."/>
<xsl:variable name="authorVar" select="../author"/>
<xsl:value-of select="."/>
<xsl:for-each select="//book[(bookshelf = $bookshelfVar)]/author[not(.=preceding::author)]">
<xsl:sort select="."/>
<xsl:apply-templates select='.'/>
</xsl:for-each>
</xsl:template>


<xsl:template match="author">
<xsl:variable name="bookshelfVar" select="../bookshelf"/>
<xsl:variable name="authorVar" select="."/>
--<xsl:value-of select="."/>
<xsl:for-each select="//book[(bookshelf = $bookshelfVar) and (author = $authorVar)]/publisher[not(.=preceding::publisher)]">
<xsl:sort select="."/>
<xsl:apply-templates select='.'/>
</xsl:for-each>
</xsl:template>


<xsl:template match="publisher">
    ----<xsl:value-of select="."/>
</xsl:template>

</xsl:stylesheet>

Can anyone see what I am doing wrong? Any help would be appreciated.

Thanks,
Glen

Current Thread