Re: [xsl] Lookup, eliminating duplicates and sorting

Subject: Re: [xsl] Lookup, eliminating duplicates and sorting
From: "Manfred Staudinger" <manfred.staudinger@xxxxxxxxx>
Date: Sat, 22 Jul 2006 01:25:12 -0700
Another perfect solution, I appreciate this very much, thanks again!
Manfred

On 21/07/06, Dimitre Novatchev <dnovatchev@xxxxxxxxx> wrote:
> I'm still fascinated by Dimitre's solution. I also tried a first modification
> (but without success): <e1> represents a response from a web service,
> but <e2> is supplied by me and fairly static. So it would make sense to
> put it in a separate document (teste2.xml), to enable the browser to cache it.
>        <e2>
>                <f c="abe" b1="abc"/>
>                <f c="abf" b1="abj"/>
>                <f c="abg" b1="abi"/>
>                <f c="abh" b1="abi"/>
>        </e2>
> The first key definition
>   <xsl:key name="kb" match="b[not(. = ../../e2/f/@c)]"  use="."/>
> I assume should become
>   <xsl:key name="kb" match="b[not(.
> =document('teste2.xml')/e2/f/@c)]"  use="."/>
> but I have no idea how to change the second
>   <xsl:key name="kb" match="@b1" use="../../../e1/b[. = current()/../@c]"/>
> How can I get a xpath expression for the (primary) source document if the
> context is in another source document?


Here is the solution to this problem -- it doesn't use any extension functions:


The following transformation:

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

<xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vdocInput" select="/"/>
 <xsl:variable name="vdocLookup" select="document('Lookup.xml')"/>

  <xsl:key name="kDist" match="b | @b1"
   use="."/>


<xsl:template match="/">


  <xsl:variable name="vOriginal" select=
    "/*/b[not(. = $vdocLookup/e2/f/@c)]"/>

  <xsl:variable name="vunqOriginal" select=
   "$vOriginal[generate-id()
              =
               generate-id(key('kDist', .)[1])
               ]"
   />

  <xsl:variable name="vReplaced"
   select="/*/b[. = $vdocLookup/e2/f/@c]"
   />

  <xsl:variable name="vExternalValues" select=
    "$vdocLookup/e2/f/@b1
         [not(. = $vOriginal)]"
    />

  <xsl:for-each select="$vdocLookup">
          <xsl:variable name="vunqAddedValues" select=
           "$vExternalValues
                          [generate-id()
                          =
                           generate-id(key('kDist',.)
                                        [../@c = $vReplaced][1]
                                       )
                           ]"
           />

          <e3>
            <xsl:for-each select="$vunqOriginal | $vunqAddedValues">
              <xsl:sort/>

                <b2><xsl:value-of select="."/></b2>
            </xsl:for-each>
          </e3>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>


when applied on this source xml document:


<e1>
        <b>abc</b>
        <b>abd</b>
        <b>abf</b>
        <b>abe</b>
        <b>abh</b>
        <b>abg</b>
        <b>abd</b>
</e1>

and with the following file

Lookup.xml:
=========
<e2>
        <f c="abe" b1="abc"/>
        <f c="abf" b1="abj"/>
        <f c="abg" b1="abi"/>
        <f c="abh" b1="abi"/>
</e2>



produces the wanted result:

<e3>
   <b2>abc</b2>
   <b2>abd</b2>
   <b2>abi</b2>
   <b2>abj</b2>
</e3>



--
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.






On 7/21/06, Manfred Staudinger <manfred.staudinger@xxxxxxxxx> wrote: > On 20/07/06, Mukul Gandhi <gandhi.mukul@xxxxxxxxx> wrote: > > Dimitre's solution is brilliant.. > > > > Here is a solution using the node-set extension function: > Sorry, I didn't state it explicitly, I need xslt 1.0 for browsers (no > extensions), > but thanks anyway. > > On 19/07/06, Dimitre Novatchev <dnovatchev@xxxxxxxxx> wrote: > > > xslt 1.0 - I've a set of nodes, for which I want > > > a. to replace some values (most will not change), then > > > b. eliminate the duplicates and sort them. > > .............................................................................. > > > The text nodes represent URI's and are then used to > > > create html links. So far I was only able to write in > > > 2 different task what should be done in one: > > > > > > > > > One simple way to do this: > > > > The following transformation: > > > > <xsl:stylesheet version="1.0" > > xmlns:xsl="http://www.w3.org/1999/XSL/Transform";> > > > > <xsl:output omit-xml-declaration="yes" indent="yes"/> > > > > <xsl:key name="kb" match="b[not(. = ../../e2/f/@c)]" use="."/> > > <xsl:key name="kb" match="@b1" use="../../../e1/b[. = current()/../@c]"/> > > <xsl:key name="kDist" match="b | @b1" use="."/> > > > > <xsl:template match="/"> > > <e3> > > <xsl:for-each select="key('kb', */e1/b)[generate-id() = > > generate-id(key('kDist', .)[1])]"> > > <xsl:sort/> > > > > <b2><xsl:value-of select="."/></b2> > > </xsl:for-each> > > </e3> > > </xsl:template> > > </xsl:stylesheet> > > > > when applied on the provided source xml document: > > > > <a> > > <e1> > > <b>abc</b> > > <b>abd</b> > > <b>abe</b> > > <b>abf</b> > > <b>abg</b> > > <b>abh</b> > > <b>abd</b> > > </e1> > > <e2> > > <f c="abe" b1="abc"/> > > <f c="abf" b1="abj"/> > > <f c="abg" b1="abi"/> > > <f c="abh" b1="abi"/> > > </e2> > > </a> > > > > produces the wanted result: > > > > <e3> > > <b2>abc</b2> > > <b2>abd</b2> > > <b2>abi</b2> > > <b2>abj</b2> > > </e3> > I'm still fascinated by Dimitre's solution. I also tried a first modification > (but without success): <e1> represents a response from a web service, > but <e2> is supplied by me and fairly static. So it would make sense to > put it in a separate document (teste2.xml), to enable the browser to cache it. > <e2> > <f c="abe" b1="abc"/> > <f c="abf" b1="abj"/> > <f c="abg" b1="abi"/> > <f c="abh" b1="abi"/> > </e2> > The first key definition > <xsl:key name="kb" match="b[not(. = ../../e2/f/@c)]" use="."/> > I assume should become > <xsl:key name="kb" match="b[not(. > =document('teste2.xml')/e2/f/@c)]" use="."/> > but I have no idea how to change the second > <xsl:key name="kb" match="@b1" use="../../../e1/b[. = current()/../@c]"/> > How can I get a xpath expression for the (primary) source document if the > context is in another source document? > Regards, Manfred

Current Thread