Re: [xsl] removing duplicates in loops

Subject: Re: [xsl] removing duplicates in loops
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Tue, 2 Apr 2002 09:44:15 +0100
Hi Yi,

> i have the following xsl and want to remove repeated education and
> honor elements. how should i achieve that?

What you're doing looks roughly OK. You're getting hold of resumeid
elements that are unique within the document with:

  /rowset/row/resumeid[not(preceding::resumeid = .)]

You're sorting these by their value (by resumeid), and creating a
resume element for each. However, you're then using *absolute* paths
to populate the content of the resume. For example:

> <first_name><xsl:value-of select="/rowset/row/fname"/></first_name>

The path /rowset/row/fname goes up to the root node of the source
document, then to the rowset element, then to the row elements and
then picks all the fname elements in the document. When you use
xsl:value-of and select a node set, xsl:value-of gives you the value
of the *first* of the nodes in the node set. So the xsl:value-of
instruction that you're using will always give you the first fname
element in the document.

You actually want the fname element from the row that holds the
resumeid that you're currently on, so you need a *relative* path --
one that doesn't start with a / -- instead:

  <first_name><xsl:value-of select="../fname"/></first_name>

If I were you, I'd actually select *row* elements rather than resumeid
elements, using preceding-sibling:: rather than the preceding:: axis,
as follows, as preceding-sibling:: is more efficient than preceding::
and as it makes the relative paths in the content of the resume
elements that you're creating easier:

  <xsl:for-each
    select="row[not(preceding-sibling::row/resumeid = resumeid)]">
    <xsl:sort select="resumeid" />
    <resume id="{resumeid}">
      <name>
        <first_name><xsl:value-of select="fname"/></first_name>
        <middle_initial><xsl:value-of select="middle"/></middle_initial>
        ...
      </name>
      ...
      <xsl:variable name="resumes"
        select="/rowset/row[resumeid = current()/resumeid]" />
      <xsl:for-each select="$resumes">
        <education>
          ...
        </education>
      </xsl:for-each>
      <xsl:for-each select="$resumes">
        <honor>
          ..
        </honor>
      </xsl:for-each>
    </resume>
  </xsl:for-each>

You might also consider using the Muenchian Method to do the grouping
that you need. See
http://www.jenitennison.com/xslt/grouping/muenchian.html for an
explanation.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


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


Current Thread