Re: [xsl] Finding distinct nodes using a function in XSLT 2.0

Subject: Re: [xsl] Finding distinct nodes using a function in XSLT 2.0
From: "Dimitre Novatchev" <dnovatchev@xxxxxxxxx>
Date: Tue, 17 Apr 2007 13:50:49 -0700
THe following transformaton s a straightforward solutionto this proble:

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";


<xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:variable name="vDoc1" as="document-node()" select="document('file:///C:/XSLT/Tests/docFoo1.xml')"/>

 <xsl:variable name="vDoc2" as="document-node()"
   select="document('file:///C:/XSLT/Tests/docFoo2.xml')"/>

 <xsl:template match="/">
  <foo>
   <xsl:for-each-group select="($vDoc1 | $vDoc2)/*/bar"
     group-by="@id">
     <xsl:sort select="current-grouping-key()"/>
     <xsl:sequence select="."/>
   </xsl:for-each-group>
  </foo>
 </xsl:template>
</xsl:stylesheet>




-- Cheers, Dimitre Novatchev --------------------------------------- Truly great madness cannot be achieved without significant intelligence. --------------------------------------- To invent, you need a good imagination and a pile of junk ------------------------------------- You've achieved success in your field when you don't know whether what you're doing is work or play


On 4/17/07, Scott Lynch <slynch@xxxxxxxxxx> wrote:
 This probably isn't the easiest way to this (suggestions welcome), but
I'm collecting data from two similarly structured source documents and
wanting to build a set of distinct nodes based on a certain attribute
value. Example XML:

doc1.xml
<foo>
 <bar id="a" />
 <bar id="b" />
 <bar id="c" />
 <bar id="d" />
 <bar id="g" />
</foo>

doc2.xml
<foo>
 <bar id="a" />
 <bar id="b" />
 <bar id="c" />
 <bar id="d" />
 <bar id="e" />
 <bar id="f" />
</foo>

Desired resulting node set:

<foo>
 <bar id="a" />
 <bar id="b" />
 <bar id="c" />
 <bar id="d" />
 <bar id="e" />
 <bar id="f" />
 <bar id="g" />
</foo>

I'm required to provide a template function (or equivalent set of
templates which returns a node set for use by various for-each
constructs in other processors) which accepts the xpath (e.g. /foo/bar)
and an index attribute (e.g. "id") as parameters and returns a node set
as seen above.

I've managed to write a function which generates a sorted union (I think
I need them sorted to find the distinct values, correct? sorry, newbie
here..), but have yet to find a way to trim the results set so that it
contains only distinct members. Here's what I have so far:

 <xsl:variable name="compare_file" select="document('doc2.xml')"/>
 <xsl:variable name="current_file" select="document('doc1.xml')"/>

 <xsl:function name="con:distinct_rows">
   <!-- Selects the distinct rows from the source docs and -->
   <!-- comparison doc                                     -->
   <xsl:param name="path"/>
   <xsl:param name="key"/>
   <xsl:variable name="source_rows"
select="$current_file/saxon:evaluate($path)"/>
   <xsl:variable name="compare_rows"
select="$compare_file/saxon:evaluate($path)"/>
   <xsl:variable name="sorted_union_rows">
     <xsl:for-each select="$source_rows | $compare_rows">
       <xsl:sort data-type="text" select="./saxon:evaluate($key)"/>
       <xsl:sequence select="."/>
     </xsl:for-each>
   </xsl:variable>
   <xsl:sequence select="$sorted_union_rows"/>
   <!-- ??? distinct node selector instead ??? -->
 </xsl:function>


Once I have the sorted union, I've tried various following/previous sibling selectors but have yet to find a command which generates the distinct node set (I can find the unique nodes based on the "id" but that's not really helping me).

Any suggestions?

thanks a lot!
Scott Lynch

Current Thread