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

Re: [xsl] Re: Ignoring Duplicates In key()


Subject: Re: [xsl] Re: Ignoring Duplicates In key()
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Thu, 14 Sep 2006 18:03:09 -0400

Bob,

The simple solution would just be

<xsl:template match="factor">
<xsl:for-each select="components/component[not(.=preceding-sibling::component)]">
<xsl:value-of select="."> ... etc ...


But maybe you're looking at more than that? This won't work if the components you wish to deduplicate aren't siblings of one another. Nor is the preceding:: axis much help, if you're trying to use keys.

Because you want to punctuate your deduplicated list, a more general solution hits up against the limitations of the one-pass limitation in XSLT 1.0. (This is because your collection of the deduplicated nodes has to occur within a single XPath if you want to punctuate it properly.) This means in 1.0 you're probably going to have to use a compound key (key the components to a concatenation of their value with a generated id for their group ancestor) and deduplicate from that set.

Or, if using 2.0, grouping constructs can be used to deduplicate:

<xsl:template match="factor">
  <xsl:for-each-group select=".//component" group-by=".">
    <xsl:value-of select="current-group()[1]"/>
    <!-- or use current-grouping-key() -->
    <xsl:if test="not(position()=last())">, </xsl:if>
  </xsl:for-each>
</xsl:template>

XSLT 2.0 makes this kind of thing much easier.

Or, in 1.0, do two passes....

Cheers,
Wendell

At 02:46 PM 9/14/2006, you wrote:
Whoops, spoke too soon. That gives a similar result when applied to
the original XSLT. More specifically, creating a new key

<xsl:key name="ComponentByValue" match="component" use="." />

       <xsl:for-each select="key('ComponentByGroup',$group)">
            <xsl:sort select="."/>
            <xsl:if test="generate-id(.) =
generate-id(key('ComponentByValue',.)[1])">

Still only generates ", gewgaw".

Rats!

Still here,
Bob Portnell
simply.bobp@xxxxxxxxx

On 9/14/06, Bob Portnell <simply.bobp@xxxxxxxxx> wrote:
Hmm. Okay, answer found:
http://www.biglist.com/lists/xsl-list/archives/200006/msg00748.html

Sorry for the distraction.
BobP

On 9/14/06, Bob Portnell <simply.bobp@xxxxxxxxx> wrote:
> Here's some fun in XSLT 1.0, using variously the MSXML 3.0 or xsltproc
> processors (result behaviors are the same).
>
> Here's some data...
>
>    <factor group="0" >
>       <number>100</number>
>       <components>
>         <component>widget</component>
>       </components>
>     </factor>
>     <factor group="1">
>       <number>110</number>
>        <components>
>         <component>widget</component>
>         <component>gewgaw</component>
>       </components>
>     </factor>
>     <factor group="1">
>       <number>112</number>
>       <components>
>         <component>gewgaw</component>
>       </components>
>     </factor>
>
> My need is to create a string of unique "components" in a "group". The
> original XSLT for this relied on a recursion structure and wasn't
> successfully blocking duplicates. My notion was to just wait for it to
> finish all the recursion (for its other needs), and then hit it with a
> key(), defined thus:
>
> (XSLT fragment)
>
> <xsl:key name="ComponentByGroup" match="component" use="../../@group" />
>
> (and then)
>
> <xsl:variable name="ComponentString">
>     <xsl:for-each
> select="key('ComponentByGroup',$group)[not(.=preceding::component)]">
>         <xsl:sort select="."/>
>         <xsl:if test="position() > 1">
>             <xsl:text>, </xsl:text>
>         </xsl:if>
>         <xsl:value-of select="." />
>     </xsl:for-each>
> </xsl:variable>
>
> The desired output would be "gewgaw, widget", but for some reason I'm
> getting only "widget." When applied to more complex data, in one case
> where 12 items should be displayed, it's correctly stopping the
> duplicates but also making two singletons vanish.
>
> The [not(.=preceding::component)] is the basic structure I found for
> reducing duplicates, but it doesn't seem to play quite nicely with the
> key() ... it's reducing too many!
>
> Thoughts welcome.
>
> Bob Portnell
> simply.bobp@xxxxxxxxx


Current Thread
Keywords