 |
| XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead. |
Welcome to the p2p.wrox.com Forums.
You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
|
|
|
|

November 21st, 2006, 08:49 PM
|
|
Friend of Wrox
|
|
Join Date: Oct 2003
Posts: 290
Thanks: 24
Thanked 0 Times in 0 Posts
|
|
KEY - GROUPING
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
|
|

November 22nd, 2006, 03:05 PM
|
|
Friend of Wrox
|
|
Join Date: Jul 2006
Posts: 430
Thanks: 28
Thanked 5 Times in 5 Posts
|
|
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
|
|

November 22nd, 2006, 07:26 PM
|
|
Friend of Wrox
|
|
Join Date: Oct 2003
Posts: 290
Thanks: 24
Thanked 0 Times in 0 Posts
|
|
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
|
|

November 22nd, 2006, 09:35 PM
|
|
Friend of Wrox
|
|
Join Date: Jul 2006
Posts: 430
Thanks: 28
Thanked 5 Times in 5 Posts
|
|
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
|
|

November 23rd, 2006, 04:45 AM
|
 |
Wrox Author
|
|
Join Date: Jun 2003
Posts: 3,074
Thanks: 1
Thanked 38 Times in 37 Posts
|
|
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:
Code:
<xsl:value-of select="key('contacts-by-surname', 'Pallone')" />
to
Code:
<xsl:value-of select="." />
--
Joe ( Microsoft MVP - XML)
|
|

November 23rd, 2006, 11:13 AM
|
|
Friend of Wrox
|
|
Join Date: Oct 2003
Posts: 290
Thanks: 24
Thanked 0 Times in 0 Posts
|
|
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="." />
</xsl:for-each>
</xsl:template>
|
|

November 23rd, 2006, 11:27 AM
|
|
Friend of Wrox
|
|
Join Date: Oct 2003
Posts: 290
Thanks: 24
Thanked 0 Times in 0 Posts
|
|
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>
|
|

November 23rd, 2006, 01:34 PM
|
 |
Wrox Author
|
|
Join Date: Jun 2003
Posts: 3,074
Thanks: 1
Thanked 38 Times in 37 Posts
|
|
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)
|
|

November 23rd, 2006, 08:14 PM
|
|
Friend of Wrox
|
|
Join Date: Oct 2003
Posts: 290
Thanks: 24
Thanked 0 Times in 0 Posts
|
|
Thanks Joe,
Yeap, I read Jeni's article first thing but was still not sure about some of the syntax
|
|

December 11th, 2006, 06:19 AM
|
|
Authorized User
|
|
Join Date: Sep 2006
Posts: 92
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
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
|
|
 |