Altova Mailing List Archives>Archive Index >xsl-list Archive Home >Recent entries >Thread Prev - RE: [xsl] Multiple matches against keys? [Thread Next] Re: [xsl] Multiple matches against keys?To: Date: 9/2/2004 2:17:00 AM 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)
<xsl:text/> <xsl:for-each select="current-group()/subject"> <xsl:text> - Task: </xsl:text> <xsl:value-of select="."/><xsl:text>
</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 | ||||||
| Company | Legal | Press | Partners | Careers | Sitemap | Contact Us | Altova Blog | Mobile | Full Site | |||
|
