xsl-list
[Top] [All Lists]

Re: Sorting problem

2005-08-31 04:47:19
David and Dimitre

Thanks for your advice, I still am missing something about keys though. The document I showed was obtained midway through a transform by building an RTF and applying xx:node-set. How then can I define a key based on @type?

Joe


From: Dimitre Novatchev <dnovatchev(_at_)gmail(_dot_)com>
Reply-To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Subject: Re: [xsl] Sorting problem
Date: Wed, 31 Aug 2005 21:36:44 +1000

On 8/31/05, Joe Fawcett <joefawcett(_at_)hotmail(_dot_)com> wrote:
> Dear All
>
> Supposing I have a document such as below =>
> <root>
>  <item type="A" subType="1"/>
>  <item type="A" subType="2"/>
>  <item type="A" subType="4"/>
>  <item type="B" subType="2"/>
>  <item type="B" subType="3"/>
>  <item type="D" subType="1"/>
>  <item type="D" subType="2"/>
>  <item type="D" subType="3"/>
>  <item type="D" subType="4"/>
>  <item type="E" subType="2"/>
>  <item type="E" subType="4"/>
> </root>
>
> This is sorted by @type and then @subType, the subType can be any positive
> number, not just an integer.
>
> I need to select the first occurrence of each item, based on its @subType,
> then the second, then the third etc, keeping them in alphabetical order
> based on @type =>
>
> <root>
>  <item type="A" subType="1"/>
>  <item type="B" subType="2"/>
>  <item type="D" subType="1"/>
>  <item type="E" subType="2"/>
>  <item type="A" subType="2"/>
>  <item type="B" subType="3"/>
>  <item type="D" subType="2"/>
>  <item type="E" subType="4"/>
>  <item type="A" subType="4"/>
>  <item type="D" subType="3"/>
>  <item type="D" subType="4"/>
> </root>
>
> This is the result of converting a RTF via xx:node-set, I am stuck with
> version 1.0, so as far as I understand I cannot use keys in the solution.
>
>
> I have produced a working solution but it seems inelegant. I first select a > distinct list of @type using pre-Muenchian methods where the type doesn't > have a preceding-sibling of the same value. I then call a template by name > recursively whereby the first pass iterates through the distinct list using
> for-each and selects the the first <item> that matches the type. This
> template is then called again and does the same for the second matching item > and continues in the same fashion. The recursion stops after being called
> sufficient times to ensure each item is matched once.
>
> Can anyone suggest anything more appealing?


This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
 exclude-result-prefixes="msxsl"
 >
        <xsl:output omit-xml-declaration="yes" indent="yes"/>

        <xsl:key name="kTypes" match="@type" use="."/>
        <xsl:key name="kItemByType" match="item" use="@type"/>

        <xsl:variable name="vDoc" select="/"/>

        <xsl:variable name="vrtfdistTypes">
          <xsl:for-each select=
            "/*/item/@type
                [generate-id()
                =
                 generate-id(key('kTypes', .)[1])
                 ]">
             <type code="{.}" count="{count(key('kTypes', .))}"/>
    </xsl:for-each>
        </xsl:variable>

<xsl:variable name="vdistTypes" select="msxsl:node-set($vrtfdistTypes)/*"/>

        <xsl:variable name="vmaxCount"
select="number($vdistTypes[not(@count &lt; $vdistTypes/@count)]/@count)"/>

        <xsl:variable name="vmaxCountTypecode"
         select="$vdistTypes[not(@count &lt; $vdistTypes/@count)]/@code[1]"/>

        <xsl:template match="/">
         <items>
          <xsl:for-each select="key('kItemByType', $vmaxCountTypecode)">
            <xsl:variable name="vcurTuple" select="position()"/>
            <xsl:for-each select="$vdistTypes">
              <xsl:variable name="vthisType" select="."/>
              <xsl:for-each select="$vDoc">
                <xsl:copy-of select=
                   "key('kItemByType', $vthisType/@code)[$vcurTuple]"/>
              </xsl:for-each>
            </xsl:for-each>
          </xsl:for-each>
         </items>
        </xsl:template>

</xsl:stylesheet>

when applied on this source xml:

<root>
        <item type="A" subType="1"/>
        <item type="A" subType="2"/>
        <item type="A" subType="4"/>
        <item type="B" subType="2"/>
        <item type="B" subType="3"/>
        <item type="D" subType="1"/>
        <item type="D" subType="2"/>
        <item type="D" subType="3"/>
        <item type="D" subType="4"/>
        <item type="E" subType="2"/>
        <item type="E" subType="4"/>
</root>

produces the wanted result:

<items>
  <item type="A" subType="1" />
  <item type="B" subType="2" />
  <item type="D" subType="1" />
  <item type="E" subType="2" />
  <item type="A" subType="2" />
  <item type="B" subType="3" />
  <item type="D" subType="2" />
  <item type="E" subType="4" />
  <item type="A" subType="4" />
  <item type="D" subType="3" />
  <item type="D" subType="4" />
</items>


Cheers,
Dimitre Novatchev.

--~------------------------------------------------------------------
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>
--~--




--~------------------------------------------------------------------
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>