Re: [xsl] Re: Re: Can grouping and sorting be done in single transformation?

Subject: Re: [xsl] Re: Re: Can grouping and sorting be done in single transformation?
From: "Herman Kwok" <herman.kwok@xxxxxxxxxxxxxxxx>
Date: Wed, 19 Nov 2003 17:05:35 +0800
Dimitre, Thanks once again. It is simply great. I had tried to solves for days.

----- Original Message -----
From: "Dimitre Novatchev" <dnovatchev@xxxxxxxxx>
Date: Tue, 18 Nov 2003 23:14:12 +0100
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: [xsl] Re: Re: Can grouping and sorting be done in single    transformation?


"Herman Kwok" <herman.kwok@xxxxxxxxxxxxxxxx> wrote in message
news:20031118102107.7888.qmail@xxxxxxxxxxxx
> Sorry for my late reply as I was out of town.
>
> Thanks Dimitre for the "exslt:node-set()" solution and Jarkko for the
"xalan:nodeset()" solution.
>
> Does it mean that there is no solution without using processor dependent
solution nor external library in XSLT 1.0?

No.

>
> Well, I am new to XSLT. I suspect that there are some limitations in node
set in XSLT. That was why the function was extended via
> using external library or via enhancing a processor. Am I correct?

No. Actually it has been proven that XSLT is Turing-complete. This means
that any algorithm, that can be implemented on a Turing machine (or on a
programming system that is as powerful or less than a Turing machine) can be
implemented in XSLT.

However, not using the xxx:node-set() extension function would be a little
more difficult and probably a little bit less efficient.

Here is a solution that does not use any extension functions. This
transformation:


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

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

 <xsl:param name="pNumInGroup" select="3"/>

 <xsl:key name="kfromID" match="item" use="generate-id()"/>

  <xsl:template match="/">
    <xsl:variable name="vIDs">
      <xsl:for-each select="/*/item">
        <xsl:sort select="@desc"/>

         <xsl:value-of select="concat(generate-id(), '|')"/>
      </xsl:for-each>
    </xsl:variable>

    <xsl:call-template name="group">
      <xsl:with-param name="pIDs" select="$vIDs"/>
      <xsl:with-param name="pNumInGroup" select="$pNumInGroup"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="group">
    <xsl:param name="pIDs" />
    <xsl:param name="pNumInGroup" select="1"/>

    <xsl:if test="contains($pIDs, '|')">
      <group>
        <xsl:call-template name="fillElements">
          <xsl:with-param name="pIDs" select="$pIDs"/>
          <xsl:with-param name="pNumInGroup" select="$pNumInGroup"/>
        </xsl:call-template>
      </group>

      <xsl:variable name="vOffset">
        <xsl:call-template name="getOffset">
          <xsl:with-param name="pIDs" select="$pIDs"/>
          <xsl:with-param name="pNumInGroup" select="$pNumInGroup"/>
        </xsl:call-template>
      </xsl:variable>

      <xsl:call-template name="group">
        <xsl:with-param name="pIDs" select="substring($pIDs, $vOffset +
1)"/>
        <xsl:with-param name="pNumInGroup" select="$pNumInGroup"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="fillElements">
    <xsl:param name="pIDs"/>
    <xsl:param name="pNumInGroup" select="1"/>

    <xsl:if test="$pNumInGroup > 0 and contains($pIDs, '|')">
      <xsl:copy-of select="key('kfromID', substring-before($pIDs, '|'))"/>

      <xsl:call-template name="fillElements">
        <xsl:with-param name="pIDs" select="substring-after($pIDs, '|')"/>
        <xsl:with-param name="pNumInGroup" select="$pNumInGroup - 1"/>
      </xsl:call-template>
    </xsl:if>

  </xsl:template>

  <xsl:template name="getOffset">
    <xsl:param name="pIDs"/>
    <xsl:param name="pNumInGroup" select="1"/>
    <xsl:param name="pResult" select="0"/>

    <xsl:choose>
      <xsl:when test="$pNumInGroup > 0 and contains($pIDs, '|')">
        <xsl:variable name="vT1" select="substring-before($pIDs, '|')"/>
        <xsl:call-template name="getOffset">
          <xsl:with-param name="pIDs" select="substring-after($pIDs, '|')"/>
          <xsl:with-param name="pNumInGroup" select="$pNumInGroup - 1"/>
          <xsl:with-param name="pResult"
               select="$pResult
                       + string-length(substring-before($pIDs, '|')) + 1"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$pResult"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

when applied on your source.xml:

<result>
  <item desc="d"/>
  <item desc="j"/>
  <item desc="k"/>
  <item desc="e"/>
  <item desc="c"/>
  <item desc="g"/>
  <item desc="h"/>
  <item desc="i"/>
  <item desc="f"/>
  <item desc="a"/>
  <item desc="b"/>
</result>

produces the wanted result:

<group>
   <item desc="a"/>
   <item desc="b"/>
   <item desc="c"/>
</group>
<group>
   <item desc="d"/>
   <item desc="e"/>
   <item desc="f"/>
</group>
<group>
   <item desc="g"/>
   <item desc="h"/>
   <item desc="i"/>
</group>
<group>
   <item desc="j"/>
   <item desc="k"/>
</group>


=====
Cheers,

Dimitre Novatchev.
http://fxsl.sourceforge.net/ -- the home of FXSL




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


-- 
__________________________________________________________
Sign-up for your own personalized E-mail at Mail.com
http://www.mail.com/?sr=signup

Search Smarter - get the new eXact Search Bar for free!
http://www.exactsearchbar.com/


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


Current Thread