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

Re: [xsl] Determining uniqueness based on mulitple element values


Subject: Re: [xsl] Determining uniqueness based on mulitple element values
From: Joerg Heinicke <joerg.heinicke@xxxxxx>
Date: Fri, 13 Dec 2002 23:32:59 +0100

Hello Tim,

the error is in your for-each loop. You use the != operator instead of not().

preceding-sibling::car/make != 'Dodge' is true, if there exists *one* <car>, which *is not* a Dodge.

not(preceding-sibling::car/make = 'Dodge') is true if there exists *no* car, which *is* a Dodge.

Furthermore there is the problem that the comparisons for make, model and year can be done to different cars. In the following example car 3 will be filtered out, because a car exists with the same make and model and another one with the same year:

  <car>
   <make>Chevy</make>
   <model>Malibu</model>
   <year>1985</year>
  </car>
  <car>
   <make>Dodge</make>
   <model>Charger</model>
   <year>1979</year>
  </car>
  <car>
   <make>Chevy</make>
   <model>Malibu</model>
   <year>1979</year>
  </car>

Your code corrected and optimized can look like:

<xsl:for-each select="carlist/dealership">
<xsl:for-each select="car">
<xsl:if test="not(preceding-sibling::car[make = current()/make and model = current()/model and year = current()/year])">
<tr>
<td>
<xsl:if test="position() = 1">
<xsl:value-of select="../@name"/>
</xsl:if>
</td>
<td><xsl:value-of select="make"/></td>
<td><xsl:value-of select="model"/></td>
<td><xsl:value-of select="year"/></td>
</tr>
</xsl:if>
</xsl:for-each>
</xsl:for-each>


I prefer the grouping via keys:

<xsl:key name="cars" match="car" use="concat(../@name, make, model, year)"/>

and later in the template:

<xsl:for-each select="carlist/dealership">
  <xsl:for-each select="car[generate-id() = generate-id(key('cars',
                           concat(../@name, make, model, year)))]">
      <tr>
        <td>
          <xsl:if test="position() = 1">
            <xsl:value-of select="../@name"/>
          </xsl:if>
        </td>
        <td><xsl:value-of select="make"/></td>
        <td><xsl:value-of select="model"/></td>
        <td><xsl:value-of select="year"/></td>
      </tr>
  </xsl:for-each>
</xsl:for-each>

This is mostly simpler and faster.

Regards,

Joerg

  <xsl:for-each select="carlist/dealership">
   <xsl:for-each select="./car">
    <xsl:choose>
     <xsl:when test="position() = 1">
      <tr>
       <td><xsl:value-of select="../@name"/></td>
       <td><xsl:value-of select="./make"/></td>
       <td><xsl:value-of select="./model"/></td>
       <td><xsl:value-of select="./year"/></td>
      </tr>
     </xsl:when>
     <xsl:when test="./make != ./preceding-sibling::car/make or ./model
!= ./preceding-sibling::car/model or ./year !=
./preceding-sibling::car/year">
      <tr>
       <td></td>
       <td><xsl:value-of select="./make"/></td>
       <td><xsl:value-of select="./model"/></td>
       <td><xsl:value-of select="./year"/></td>
      </tr>
     </xsl:when>
     <xsl:otherwise />
    </xsl:choose>
   </xsl:for-each>
  </xsl:for-each>


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



Current Thread