[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: 2 unique lists


Subject: Re: 2 unique lists
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Mon, 07 Aug 2000 19:34:32 +0100

Matt,

Your two solutions are both just slightly mis-implemented such that neither
of them work, for the same basic reason: you are looking at the whole
document rather than just the dates for the person you're interested in.

First, then:

><xsl:template match="person">
>  <xsl:value-of select="@name"/><xsl:text>: </xsl:text>
>  <xsl:for-each select="date[ not( . = preceding::date )]">
>    <xsl:value-of select="."/>
>    <xsl:if test="not(position()=last())">, </xsl:if>
>  </xsl:for-each>
></xsl:template>

If you look at the dates you're selecting there, you're looking for any
date that does not have a value equal to the value of a date that precedes
it.  Axes all work on the *source* rather than on the *current node list*.
Therefore the 'precede' axis is finding all the preceding dates in the
document.  For 'person2', this includes all the dates for 'person1' - all
of the dates are replicated for the second person, so none of the dates are
output.  In this case, you can change 'preceding' to 'preceding-sibling'
and it will work because all the dates that you're interested in have the
same parent:

<xsl:template match="person">
  <xsl:value-of select="@name"/><xsl:text>: </xsl:text>
  <xsl:for-each select="date[ not( . = preceding-sibling::date )]">
    <xsl:value-of select="."/>
    <xsl:if test="not(position()=last())">, </xsl:if>
  </xsl:for-each>
</xsl:template>

Second:

><xsl:key name="thedate" match="date" use="."/>
>
><xsl:template match="person">
>  <xsl:value-of select="@name"/><xsl:text>: </xsl:text>
>  <xsl:for-each select="date[generate-id(.) =
generate-id(key('thedate',.)[1])]">
>    <xsl:value-of select="."/>
>    <xsl:if test="not(position()=last())">, </xsl:if>
>  </xsl:for-each>
></xsl:template>

Within your key, each of the dates is indexed according to the value of the
date.  They are *all* indexed in document order, so all the 'Feb2000' dates
are grouped together under the same key, *all* of them, whether they are
under 'person1' or 'person2'.  When you retrieve the first date with the
same value using the key, you get the first one that appears *in the
document* rather than (again) under the particular person.

You can get around this by instead choosing the first of the set of dates
(retrieved via the key) that have the same person @name as the current
person @name:

<xsl:key name="thedate" match="date" use="."/>

<xsl:template match="person">
  <xsl:value-of select="@name"/><xsl:text>: </xsl:text>
  <xsl:for-each select="date[generate-id(.) =
generate-id(key('thedate',.)[../@name = current()/@name][1])]">
    <xsl:value-of select="."/>
    <xsl:if test="not(position()=last())">, </xsl:if>
  </xsl:for-each>
</xsl:template>

Alternatively, you can set the key to use as an index a combined value
based on the value of the date and the person's @name, and then retrieve
only those dates that have this value:

<xsl:key name="thedate" match="date" use="concat(../@name, '::', .)"/>

<xsl:template match="person">
  <xsl:value-of select="@name"/><xsl:text>: </xsl:text>
  <xsl:for-each select="date[generate-id(.) =
generate-id(key('thedate',concat(../@name, '::', .))[1])]">
    <xsl:value-of select="."/>
    <xsl:if test="not(position()=last())">, </xsl:if>
  </xsl:for-each>
</xsl:template>

I hope this helps,

Jeni

Dr Jeni Tennison
Epistemics Ltd * Strelley Hall * Nottingham * NG8 6PE
tel: 0115 906 1301 * fax: 0115 906 1304 * email: jeni.tennison@xxxxxxxxxxxxxxxx


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list



Current Thread