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

June 30th, 2008, 12:34 PM
|
|
Registered User
|
|
Join Date: Jun 2008
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Muenchian Grouping on individual nodes in xslt1.0
Hi,
I am trying to do grouping on nodesets. Below given is my input xml (This is a sample i took from my original problem in order to make the problem simpler)
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Level>
<Level1>
<Field11>sdfds</Field11>
<Field12>dfdf</Field12>
</Level1>
<Level2>
<Field21>sdfds</Field21>
<Field22>dfdf</Field22>
</Level2>
<Level1>
<Field11>sdfds</Field11>
<Field12>dfdf</Field12>
</Level1>
</Level>
<Level>
<Level1>
<Field11>sdfds</Field11>
<Field12>dfdf</Field12>
</Level1>
<Level2>
<Field21>sdfds</Field21>
<Field22>dfdf</Field22>
</Level2>
<Level3>
<Field31>sdfds</Field31>
<Field32>dfdf</Field32>
</Level3>
<Level2>
<Field21>sdfds</Field21>
<Field22>dfdf</Field22>
</Level2>
</Level>
</Root>
I would like to get the output as in the following order (for my complete solution this order is very important)
<Level1>
<Field11>sdfds</Field11>
<Field12>dfdf</Field12>
</Level1>
<Level1>
<Field11>sdfds</Field11>
<Field12>dfdf</Field12>
</Level1>
<Level2>
<Field21>sdfds</Field21>
<Field22>dfdf</Field22>
</Level2>
<Level1>
<Field11>sdfds</Field11>
<Field12>dfdf</Field12>
</Level1>
<Level2>
<Field21>sdfds</Field21>
<Field22>dfdf</Field22>
</Level2>
<Level2>
<Field21>sdfds</Field21>
<Field22>dfdf</Field22>
</Level2>
<Level3>
<Field31>sdfds</Field31>
<Field32>dfdf</Field32>
</Level3>
I have used Muenchian Grouping to group it and i am getting
<Level1>
<Field11>sdfds</Field11>
<Field12>dfdf</Field12>
</Level1>
<Level1>
<Field11>sdfds</Field11>
<Field12>dfdf</Field12>
</Level1>
<Level1>
<Field11>sdfds</Field11>
<Field12>dfdf</Field12>
</Level1>
<Level2>
<Field21>sdfds</Field21>
<Field22>dfdf</Field22>
</Level2>
<Level2>
<Field21>sdfds</Field21>
<Field22>dfdf</Field22>
</Level2>
<Level2>
<Field21>sdfds</Field21>
<Field22>dfdf</Field22>
</Level2>
<Level3>
<Field31>sdfds</Field31>
<Field32>dfdf</Field32>
</Level3>
and this is my stylesheet
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" />
<xsl:key name="levels" match="Level/*" use="local-name ()" />
<xsl:template match="/">
<xsl:for-each select="//Level/*[generate-id() = generate-id(key('levels', local-name())[1])]">
<xsl:sort select="local-name ()" />
<xsl:variable name="localN" select="local-name ()" />
<xsl:for-each select="key ('levels', $localN )">
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I understand the output is because the key is applied to the document instead of each individual level element. Is there a way by which i can apply the key to each individual level element?
Thanks,
sudhish
|
|

June 30th, 2008, 01:33 PM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
Since the order of the output is very important, it's important that we can tell which output element results from which input. In your example there are three Level1 elements, which appear at positions 1, 3, and 4 in the input, but at positions 1, 2 and 4 in the output. Since they all have identical content it's very hard to see what the correspondence is.
Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
|
|

June 30th, 2008, 02:09 PM
|
|
Registered User
|
|
Join Date: Jun 2008
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Hi Michael,
Thanks for responding. I actually would like to group elements inside each parent level element. But in my output i don't really require the level element (It can appear though). So the order is as it appears in the parent level element.
The desired output with level element (level element is not really required, thats why i omitted that code from my xsl)
<Level>
<Level1>
<Field11>sdfds</Field11>
<Field12>dfdf</Field12>
</Level1>
<Level1>
<Field11>sdfds</Field11>
<Field12>dfdf</Field12>
</Level1>
<Level2>
<Field21>sdfds</Field21>
<Field22>dfdf</Field22>
</Level2>
</Level>
<Level>
<Level1>
<Field11>sdfds</Field11>
<Field12>dfdf</Field12>
</Level1>
<Level2>
<Field21>sdfds</Field21>
<Field22>dfdf</Field22>
</Level2>
<Level2>
<Field21>sdfds</Field21>
<Field22>dfdf</Field22>
</Level2>
<Level3>
<Field31>sdfds</Field31>
<Field32>dfdf</Field32>
</Level3>
</Level>
I am looking for a way to group elements inside each Level element.
Thanks,
Sudhish
|
|

July 1st, 2008, 01:20 AM
|
|
Authorized User
|
|
Join Date: May 2008
Posts: 32
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="Root">
<root>
<xsl:apply-templates select="Level"/>
</root>
</xsl:template>
<xsl:template match="Level">
<xsl:apply-templates select="node()" mode="levels">
<xsl:sort select="name()"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="node()" mode="levels">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
|
|

July 1st, 2008, 03:38 AM
|
|
Registered User
|
|
Join Date: Jun 2008
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Thank You Volder.
I apologize for not giving a clear problem statement. I wanted to simplify the question for better clarity. So i tried to focus my question on the point where i am struck. By doing so, i forgot to mention an important aspect of the problem.
Actually Grouping is important here as i have to do some operations like count (this is only one case) on these element groups (for example, level1 element group in first level element).
I tried concatenating generate-id of parent Level element with the local-name of child Level* element in xsl:key use, but its not working.
Thanks,
Sudhish
|
|

July 1st, 2008, 06:21 AM
|
|
Authorized User
|
|
Join Date: May 2008
Posts: 32
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
what do you mean by "grouping" here? your elements are already grouped initially inside every separate element 'Level'.
I thought you were talking about proper ordering inside every Level, but now it seems for me that you were asking about smth diffirent.
So it is better if you clearly describe what you need, based on your first input sample, and we could help you.
|
|

July 1st, 2008, 07:02 AM
|
|
Registered User
|
|
Join Date: Jun 2008
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Volder,
I mean, Grouping similar elements inside each level element and do some operations on those elements.
For example,
<Level>
<Level1>
<Field11>sdfds</Field11>
<Field12>dfdf</Field12>
</Level1>
<Level2>
<Field21>sdfds</Field21>
<Field22>dfdf</Field22>
</Level2>
<Level1>
<Field11>sdfds</Field11>
<Field12>dfdf</Field12>
</Level1>
</Level>
In the above xml has a level element containing level1, level2 and level1 child elements. I would like to group these elemenets and peform operations on level1 group and level2 group (if any).
Similary my next level element in the xml contains level1, level2, level3 and level2 elements. I would like group these elements and perform operations on level1 group, level2 group and level3 group.
Hope this makes everything clear... I apologize for not making myself clear on the previous posts..
Thanks,
Sudhish
|
|

July 1st, 2008, 08:41 AM
|
|
Friend of Wrox
|
|
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
|
|
I think the stylesheet posted earlier that sorts the Level/* elements does what you want.
If you really want to apply Muenchian grouping with a key that concatenates the generated id of the parent element with the name then here is a sample stylesheet:
Code:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes"/>
<xsl:key name="by-level"
match="Level/*"
use="concat(generate-id(..), '_', local-name())"/>
<xsl:template match="Root">
<xsl:copy>
<xsl:apply-templates select="Level"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Level">
<xsl:apply-templates select="*[generate-id() = generate-id(key('by-level', concat(generate-id(..), '_', local-name()))[1])]">
<xsl:sort select="local-name()" data-type="text"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="Level/*">
<xsl:copy-of select="key('by-level', concat(generate-id(..), '_', local-name()))"/>
</xsl:template>
</xsl:stylesheet>
As far as I can tell it gives the described output with your XML sample input.
--
Martin Honnen
Microsoft MVP - XML
|
|

July 1st, 2008, 09:53 AM
|
|
Authorized User
|
|
Join Date: May 2008
Posts: 32
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
[quot]Hope this makes everything clear...[/quot]
sorry, buddy, but it is still unclear for me and it would be nice - if you give an expected output for the input in your last reply.
|
|

July 1st, 2008, 10:32 AM
|
|
Registered User
|
|
Join Date: Jun 2008
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Martin Thanks for your post. Thats exactly what i was looking for..
|
|
 |