Subject: KEY - GROUPING
Posted By: pallone Post Date: 11/21/2006 7:49:11 PM
Hi,

NOTE: I use XSLT 1.0 and MSXML

I am reading Jeni's tutorial on grouping using the Muenchian Method to see if I can understand it but have a few questions about it.

This is the example XML

<?xml version="1.0" encoding="UTF-8"?>
<records>
  <contact id="0001">
    <title>Mr</title>
    <forename>John</forename>
    <surname>Smith</surname>
  </contact>
  <contact id="0002">
    <title>Dr</title>
    <forename>Amy</forename>
    <surname>Jones</surname>
  </contact>
  <contact id="0003">
    <title>Mr</title>
    <forename>Colin</forename>
    <surname>Pallone</surname>
  </contact>
  <contact id="0004">
    <title>Miss</title>
    <forename>Jessica</forename>
    <surname>Pallone</surname>
  </contact>
</records>

I started with this simple XSLT to see what is going on:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="contacts-by-surname" match="contact" use="surname" />
<xsl:template match="records">
<xsl:for-each select="key('contacts-by-surname', 'Pallone')">
  <xsl:value-of select="key('contacts-by-surname', 'Pallone')" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

For my surprise, this code is repeating the same node. This is the output I get even though I am using a for loop to loop through the key that has a surname node with Pallone as value.

MrColinPalloneMrColinPallone

I thought the output would be:

MrColinPalloneMissJessicaPallone

since I have two <surname> nodes with different <forename> nodes.

1 - I would like to understand why this is happening.


Further in the tutorial, this construction is used:

<xsl:for-each select="contact[count(. | key('contacts-by-surname', surname)[1]) = 1]">

2 - I do not understand why we have to use the count() function here.

3 - Also count(.) - means count the context node right ?

4 - What does the '|' mean in this expression?

5 - After the '|' we have this expression but the tutorial does not explain in detail what it means.
       key('contacts-by-surname', surname)[1]) = 1]


I would be very grateful if you could help to understand it.

Cheers,

CPall
Reply By: bonekrusher Reply Date: 11/22/2006 2:05:46 PM
I would suggest picking up the following:

Beginning XSLT 2.0 From Novice to Professional  - Jeni Tennison

Beginning XSLT - Jeni Tennison

XSLT 2.0 Programmer's Reference, 3rd Edition by Michael Kay

Learning XSLT By Michael Fitzgerald


Reply By: pallone Reply Date: 11/22/2006 6:26:32 PM
Hi bonekrusher,

I am still using XSLT 1.0. and have already read Michael Kay's XSLT 1.0 book. But we don't learn everything at once. The reason why I am trying to understand this is because I am having speed problems with one of my transformations and think this can help.

Also, I managed to find some info online and have a better understanding now.

We use '|' to compare the context node to the one in the key. Right ?

One thing howevers I am still not sure about is why we use this - [1])=1

I think the [1] is like an array so we select the first nonde(but what first node the context or the key ?)

Also why we need to use count()=1 ?

Please could you elaborate a bit on that.

Cheers

CPall





)[1]) = 1


Reply By: bonekrusher Reply Date: 11/22/2006 8:35:40 PM
No worries, CPall, I am learning also. I was suggesting those books because they could help you a lot. I can try to help:

'|' - This and like saying "AND". This an an XPath Operator. It computes two node-sets

For the other questions, can you post the whole code? Just seeing <xsl:for-each select="contact[count(. | key('contacts-by-surname', surname)[1]) = 1]"> doesnt help me much. I'll try to help, if you post the whole template.

Regards
Bones



Reply By: joefawcett Reply Date: 11/23/2006 3:45:30 AM
You are asking for all the contacts that have a surname Pallone. You are then outputting the xsl:value-of all the contacts that have have the surname Pallone. This consists of two nodes therefore value-of outputs the text value of the first node.
Change:
<xsl:value-of select="key('contacts-by-surname', 'Pallone')" />
to
<xsl:value-of select="." />


--

Joe (Microsoft MVP - XML)
Reply By: pallone Reply Date: 11/23/2006 10:13:30 AM
Hi Bones, Joe,

Thanks for your reply.

Joe, thanks for the correction. However, could you plese clarify to me the points I made in my previous email. I would like to understand how it works in detail.

Here is the code Bones:

<xsl:key name="contacts-by-surname" match="contact" use="surname" />

<xsl:template match="records">
<xsl:for-each select="key('contacts-by-surname', 'Pallone')">
<!--<xsl:value-of select="key('contacts-by-surname', 'Pallone')" />-->
<xsl:value-of select="." />
</xsl:for-each>
</xsl:template>
Reply By: pallone Reply Date: 11/23/2006 10:27:11 AM
Sorry Bones,

This is the code I am using inside the template:

<xsl:for-each select="contact[count(. | key('contacts-by-surname', surname)[1]) = 1]">
 - <xsl:value-of select="surname" />,<br />
</xsl:for-each>
Reply By: joefawcett Reply Date: 11/23/2006 12:34:34 PM
Have you read through the article on grouping at Jeni Tennison's site? The link is in the first post in this forum. The | operator is used to union nodes. If you union two nodes that are actually the same then you get a set with only one node, by comparing the count to one you then know that the first node returned from the key is the context node. That way you get a distinct list of surnames.

--

Joe (Microsoft MVP - XML)
Reply By: pallone Reply Date: 11/23/2006 7:14:01 PM
Thanks Joe,

Yeap, I read Jeni's article first thing but was still not sure about some of the syntax
Reply By: asearle Reply Date: 12/11/2006 5:19:34 AM
Hi guys,

This is exactly the same issue that I have and I have found that switching from generate-id() to ...

 <xsl:for-each select="contact[count(. | key('contacts-by-surname', surname)[1]) = 1]">

... (as Pallone has quoted) can (in some circumstances) really reduce response times.

However, my problem is that I need to also incorporate a filter and am having trouble getting the filter to return the right values.  Maybe you guys can check out my thread (speed and grouping) and see if it helps you and if you have any ideas on filter syntax.

Many thanks,
Alan Searle


Go to topic 53454

Return to index page 97
Return to index page 96
Return to index page 95
Return to index page 94
Return to index page 93
Return to index page 92
Return to index page 91
Return to index page 90
Return to index page 89
Return to index page 88