xsl-list
[Top] [All Lists]

Re: Multiple matches against keys?

2004-09-01 19:16:00
Wow -- that's appealingly simple. What I actually want is the following:

- 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: (1 tasks)
   - Task: This is a call to be made from work

I think that's what you had in mind, but the last context label should be "work", not 
"work call". I'm using libxslt tho so I don't think the XSLT 2.0 solution will work for 
me yet.

Ramon

Andrew Welch wrote:

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

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