xsl-list
[Top] [All Lists]

Re: [xsl] eliminating duplicates

2007-05-11 04:47:46
Hi George,

Very nice, but it isn't stable in all circumstances (nor was mine for that fact). Consider the following distinct values:

   <edge source="IGetterC" target="Getter" dependency="positive"/>
   <edge source="IGetter" target="CGetter" dependency="positive"/>

these will be seen as non-distinct when you use concat() the way you propose. A better solution might be to introduce a separator:

   concat(@dependency, '-', @source, '-', @target)

but still, if the source'd be like this, it won't help much:

   <edge source="IGetter-C" target="Getter" dependency="positive"/>
   <edge source="IGetter" target="C-Getter" dependency="positive"/>

Of course, if you know something about your source XML this may not be a problem at all. If it is a problem, you may want to choose the concat-approach with a private use character like &#F0001; or something even uglier, which is quite unlikely to occur in a source file, but will make your code less readable or pretty:

   <xsl:copy-of select="
    for $i in
distinct-values(*/concat(@dependency, '&#F0001; ', @source, '&#F0001;', @target)) return *[$i=concat(@dependency, '&#F0001; ', @source, '&#F0001; ', @target)][1]"/>


In fact, all we are doing here is trying to stop a boat from making water by using wet clothes... Here's another attempt at a oneliner that is likely to work for de-duping this kind of sequences in XSLT 2.0 and it does not have the drawbacks of the previous attempts:

<xsl:copy-of select="edge[not(some $i in preceding-sibling::edge satisfies deep-equal($i, .))]" />

if performance is important, this may be a tidbit faster but it may change the order of the result:

<xsl:copy-of select="edge[not(some $i in unordered(preceding-sibling::edge) satisfies deep-equal($i, .))]" />

this may be equivalent to the fn:unordered method above, but in practice, I found that the fn:unordered did not introduce a difference in the results with saxon (though MK's book implied that document order would be applied on precding-sibling when using fn:unordered... )

<xsl:copy-of select="edge[not(some $i in following-sibling::edge satisfies deep-equal($i, .))]" />



Cheers,
-- Abel Braaksma

George Cristian Bina wrote:
Here it is another 2.0 approach that gives the result in one instruction :) assumming the edge elements are children of the current context node:

<xsl:copy-of select="
 for $i in
     distinct-values(*/concat(@dependency, @source, @target))
           return *[$i=concat(@dependency, @source, @target)][1]"/>

If you define a key using concat(@dependency, @source, @target) and matching edge elements

<xsl:key name="e" match="edge"
    use="concat(@dependency, @source, @target)"/>

then the return will be

           return key('e',$i)[1]"/>

Best Regards,
George


--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

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