[xsl] Distinct values with XPath query in stylesheet

Subject: [xsl] Distinct values with XPath query in stylesheet
From: "Matthew Hailstone" <matthew.hailstone@xxxxxxxxx>
Date: Tue, 16 Sep 2008 09:45:38 -0600
For example, the desired list for the "Fee Two" Fee Description is:
0.50
5.00
0.00

The result from the following XPath query is:
//two/FEES/FEE[@Description='Fee Two' and
not(@*[name()='Amount']=preceding::FEE/@*[name()='Amount'])]
0.50
0.00

The XPath query in question is:
//two/FEES/FEE[@Description=$feeName and
not(@*[name()=$feeValueAttr]=preceding::FEE/@*[name()=$feeValueAttr])]
which is found in the "fee-type-defs" template.

Any help at debugging this or suggesting the correct or better way to
find a distinct value list would be greatly appreciated.

Thanks!
Matthew

Here is the source XML:
-----------------------------------------------------------------------------------------------------------
<one>
	<two Description="two one" ID="21">
		<FEES TotalAmount="7.00">
			<FEE Description="Fee One" Amount="5.00" />
			<FEE Description="Fee Two" Amount="0.50" />
			<FEE Description="Page Count" Pages="10" />
		</FEES>
	</two>
	<two Description="two two" ID="22">
		<FEES TotalAmount="7.00">
			<FEE Description="Fee One" Amount="5.00" />
			<FEE Description="Fee Two" Amount="0.50" />
			<FEE Description="Page Count" Pages="10" />
		</FEES>
	</two>
	<two Description="two three" ID="23">
		<FEES TotalAmount="12.00">
			<FEE Description="Fee One" Amount="10.00" />
			<FEE Description="Fee Two" Amount="5.00" />
			<FEE Description="Page Count" Pages="2" />
		</FEES>
	</two>
	<two Description="two four" ID="24">
		<FEES TotalAmount="12.00">
			<FEE Description="Fee One" Amount="10.00" />
			<FEE Description="Fee Two" Amount="5.00" />
			<FEE Description="Page Count" Pages="2" />
		</FEES>
	</two>
	<two Description="two five" ID="25">
		<FEES TotalAmount="7.00">
			<FEE Description="Fee One" Amount="5.00" />
			<FEE Description="Fee Two" Amount="0.50" />
			<FEE Description="Page Count" Pages="10" />
		</FEES>
	</two>
	<two Description="two six" ID="26">
		<FEES TotalAmount="7.00">
			<FEE Description="Fee One" Amount="5.00" />
			<FEE Description="Fee Two" Amount="0.00" />
			<FEE Description="Page Count" Pages="10" />
		</FEES>
		<CONSIDERATION Required="Yes"/>
	</two>
	<two Description="two seven" ID="27">
		<FEES TotalAmount="12.00">
			<FEE Description="Fee One" Amount="10.00" />
			<FEE Description="Fee Two" Amount="5.00" />
			<FEE Description="Page Count" Pages="2" />
		</FEES>
	</two>
	<two Description="two eight" ID="28">
		<FEES TotalAmount="12.00">
			<FEE Description="Fee One" Amount="10.00" />
			<FEE Description="Fee Two" Amount="5.00" />
			<FEE Description="Page Count" Pages="2" />
		</FEES>
	</two>
	<two Description="two nine" ID="29">
		<FEES TotalAmount="12.00">
			<FEE Description="Fee One" Amount="10.00" />
			<FEE Description="Fee Two" Amount="5.00" />
			<FEE Description="Page Count" Pages="2" />
		</FEES>
	</two>
	<two Description="two ten" ID="210">
		<FEES TotalAmount="12.00">
			<FEE Description="Fee One" Amount="10.00" />
			<FEE Description="Fee Two" Amount="5.00" />
			<FEE Description="Page Count" Pages="2" />
		</FEES>
	</two>
	<two Description="two eleven" ID="211">
		<FEES TotalAmount="7.00">
			<FEE Description="Fee One" Amount="5.00" />
			<FEE Description="Fee Two" Amount="0.50" />
			<FEE Description="Page Count" Pages="10" />
		</FEES>
	</two>
	<two Description="two twelve" ID="212">
		<FEES TotalAmount="7.00">
			<FEE Description="Fee One" Amount="5.00" />
			<FEE Description="Fee Two" Amount="0.50" />
			<FEE Description="Page Count" Pages="10" />
		</FEES>
	</two>
</one>
-----------------------------------------------------------------------------------------------------------

Here is the stylesheet:
-----------------------------------------------------------------------------------------------------------
<!DOCTYPE stylesheet [
<!ENTITY space "<xsl:text> </xsl:text>">
<!ENTITY cr "<xsl:text>
</xsl:text>">
]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">
	<xsl:template match="/one">
		<xsl:apply-templates select="two" mode="sort-Fees">
			<xsl:sort select="@Description"/>
		</xsl:apply-templates>
		<xsl:text>Name,ID</xsl:text>&cr;
		<xsl:apply-templates select="two" mode="sort-two">
			<xsl:sort select="@Description"/>
		</xsl:apply-templates>
	</xsl:template>

	<xsl:template match="two" mode="sort-Fees">
		<xsl:apply-templates
select="FEES/FEE[not(./@Description=preceding::FEE/@Description)]"
mode="fee-type-defs"/>
	</xsl:template>
	
	<xsl:template match="two" mode="sort-two">
        <xsl:value-of
select="@Description"/><xsl:text>,</xsl:text><xsl:value-of
select="@ID"/><xsl:text></xsl:text>&cr;
    </xsl:template>

	<!-- Fee Type Definitions -->	
	<xsl:template match="FEE" mode="fee-type-defs">
		<xsl:variable name="feeName"><xsl:call-template
name="fee-type-name"><xsl:with-param name="feeAttributes"
select="."/></xsl:call-template></xsl:variable>
		<xsl:variable name="feeValueAttr"><xsl:call-template
name="fee-type-value"><xsl:with-param name="feeAttributes"
select="."/></xsl:call-template></xsl:variable>
		<xsl:value-of
select="$feeName"/><xsl:text>,Amount</xsl:text>&space;<xsl:text>Expression,"(type_code?</xsl:text>
	 	<xsl:apply-templates select="//two/FEES/FEE[@Description=$feeName
and not(@*[name()=$feeValueAttr]=preceding::FEE/@*[name()=$feeValueAttr])]"
mode="fee-type-values">
			<xsl:with-param name="feeDescription" select="$feeName"/>
			<xsl:with-param name="feeValueAttrName" select="$feeValueAttr"/>
	 	</xsl:apply-templates>
	 	<xsl:text>0)</xsl:text>&cr;
	</xsl:template>

	<!-- Get Fee Type Name -->
	<xsl:template name="fee-type-name">
		<xsl:param name="feeAttributes"/>
	 	<xsl:for-each select="@*">
			<xsl:if test="name()='Description'"><xsl:value-of select="."/></xsl:if>
	 	</xsl:for-each>
	</xsl:template>

	<!-- Get Fee Type Value Attribute Name -->
	<xsl:template name="fee-type-value">
		<xsl:param name="feeAttributes"/>
	 	<xsl:for-each select="@*">
			<xsl:if test="not(name()='Description')"><xsl:value-of
select="name()"/></xsl:if>
	 	</xsl:for-each>
	</xsl:template>
	
	<!-- Fee Type Values -->	
	<xsl:template match="FEE" mode="fee-type-values">
		<xsl:param name="feeDescription"/>
		<xsl:param name="feeValueAttrName"/>
		<xsl:variable name="feeValue" select="./@*[name()=$feeValueAttrName]"/>
		<!--
		Fee Description:<xsl:value-of select="$feeDescription"/>&cr;
		Fee Value Attribute Name:<xsl:value-of select="$feeValueAttrName"/>&cr;
		Fee Value:<xsl:value-of select="$feeValue"/>&cr;
		 -->
		<xsl:text>&space;[</xsl:text>
		<xsl:for-each select="//two[FEES/FEE[@Description=$feeDescription
and @*[name()=$feeValueAttrName]=$feeValue]]">
			<xsl:sort select="@Description"/>
			<xsl:text>""</xsl:text><xsl:value-of
select="@ID"/><xsl:text>""</xsl:text><xsl:if
test="not(position()=last())"><xsl:text>, </xsl:text></xsl:if>
		</xsl:for-each>
		<xsl:text>],</xsl:text><xsl:value-of
select="$feeValue"/><xsl:text>:</xsl:text>
	</xsl:template>
	
</xsl:stylesheet>
-----------------------------------------------------------------------------------------------------------

Current Thread