xsl-list
[Top] [All Lists]

Re: Determining uniqueness based on mulitple element values

2002-12-16 06:42:18
Joerg,

This is the second time you've saved me.

Thanks,
Tim

Joerg Heinicke wrote:

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


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



<Prev in Thread] Current Thread [Next in Thread>