[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

RE: Multiple matches against keys?

Subject: RE: Multiple matches against keys?
From: "Andrew Welch" <ajwelch@xxxxxxxxxxxxxxx>
Date: Tue, 31 Aug 2004 10:32:51 +0100
xsl template multiple matches
> I'm trying to group and sort a list of tasks by category, where one
> <task> may have multiple categories identified by <context>
> tags. I find
> that I get different results depending on the ordering in the
> source XML:
>
> <tasks>
>     <task>
>         <subject>This is to be done at home</subject>
>         <context>home</context>
>     </task>
>     <task>
>         <subject>No context so skip this one.</subject>
>     </task>
>     <task>
>         <subject>Make a phone call</subject>
>         <context>call</context>
>     </task>
>     <task>
>         <subject>This is to be done at home, and is a phone
> call</subject>
>         <context>home</context>
>         <context>call</context>
>     </task>
>     <task>
>         <subject>This is a call to be made from work</subject>
>         <context>work</context>
>         <context>call</context>
>     </task>
> </tasks>
>
> Using the following XSLT, I get what I want:
>
> <xsl:stylesheet version="1.0"
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
>     <xsl:output method="xml" version="1.0" encoding="UTF-8"
> indent="yes"/>
>     <xsl:key name="tasks-by-context" match="task" use="context"/>
>     <xsl:template match="/">
>         <ul>
>             <xsl:for-each select="//task[count(. |
> key('tasks-by-context', context)[1]) = 1][count(context)>0]">
>                 <xsl:sort select="subject"/>
>                 <xsl:variable name="c" select="context"/>
>                 <li>
>                     CONTEXT: <xsl:value-of select="$c"/>:
> (<xsl:value-of
> select="count(key('tasks-by-context',$c))"/> tasks)
>                     </li>
>                 <ul>
>                     <xsl:for-each
> select="key('tasks-by-context', $c)">
>                             <li>
>                                     Task : <xsl:value-of
> select="subject"/>
>                             </li>
>                     </xsl:for-each>
>                 </ul>
>             </xsl:for-each>
>         </ul>
>     </xsl:template>
> </xsl:stylesheet>
>
> As I'm skipping uncategorized tasks (i.e. with no <context>
> children), I
> get the following output:
>
> - CONTEXT: call: (3 tasks)
>     - Task : Make a phone call
>     - Task : This is to be done at home, and is a phone call
>     - Task : This is a call to be made from work
> - CONTEXT: home: (2 tasks)
>     - Task : This is to be done at home
>     - Task : This is to be done at home, and is a phone call
>
> However, this behavior differs if the original <task>
> elements are in a
> different order. For example, moving the "Make a phone call"
> task to the
> end of the <tasks> list reduces the output to the following:
>
> - CONTEXT: home: (2 tasks)
>     - Task : This is to be done at home
>     - Task : This is to be done at home, and is a phone call
>
> So it looks like my key definition is no longer picking up
> "call" as a
> valid key item. I'm actually not sure whether I'm using the <xsl:key>
> tag correctly here -- will it match and index a single <task> node
> multiple times if it contains multiple tags?



Here's an XSLT 2.0 solution, although I'm not sure your desired output
is correct:

<xsl:template match="/">
    <xsl:for-each-group select="/tasks/task" group-by="context">
        <xsl:text>- CONTEXT: </xsl:text>
        <xsl:value-of select="context"/>: (<xsl:text/>
        <xsl:value-of select="count(current-group())"/>
tasks)&#xa;<xsl:text/>
        <xsl:for-each select="current-group()/subject">
            <xsl:text>    - Task: </xsl:text>
            <xsl:value-of select="."/><xsl:text>&#xa;</xsl:text>
        </xsl:for-each>
    </xsl:for-each-group>
</xsl:template>

This will produce:

- CONTEXT: call: (3 tasks)
    - Task: Make a phone call
    - Task: This is to be done at home, and is a phone call
    - Task: This is a call to be made from work
- CONTEXT: home: (2 tasks)
    - Task: This is to be done at home
    - Task: This is to be done at home, and is a phone call
- CONTEXT: work call: (1 tasks)
    - Task: This is a call to be made from work

Whereas your desired output is:

- CONTEXT: call: (3 tasks)
    - Task : Make a phone call
    - Task : This is to be done at home, and is a phone call
    - Task : This is a call to be made from work
- CONTEXT: home: (2 tasks)
    - Task : This is to be done at home
    - Task : This is to be done at home, and is a phone call

Wouldn't you want to output the 'work' context as well?

cheers
andrew

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.