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

April 19th, 2011, 12:55 PM
|
|
Friend of Wrox
|
|
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
|
|
Well the input XML you posted has "Result" elements you want to group, so the key should be
Code:
<xsl:key name="Results-by-name" match="Result" use="Name"/>
using match="contact" does not make any sense.
Furthermore you want to group the Result childen of the Results element so you need to put the grouping code in there e.g.
Code:
<xsl:template match="Results">
<xsl:copy>
<xsl:apply-templates select="Result[generate-id() = generate-id(key('Results-by-name', Name)[1])]" mode="group"/>
</xsl:copy>
</xsl:template>
then in the grouping template use
Code:
<xsl:template match="Result" mode="group">
<xsl:for-each select="key('Results-by-name', Name)">
<xsl:sort select="ModifyDate + ModifyTime" data-type="number" order="descending"/>
<xsl:if test="position() = 1">
<xsl:apply-templates select="."/>
</xsl:if>
</xsl:for-each>
</xsl:template>
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
Last edited by Martin Honnen; April 19th, 2011 at 01:01 PM..
Reason: fixing key call to properly name the defined key
|
|

April 20th, 2011, 12:18 PM
|
|
Authorized User
|
|
Join Date: Apr 2008
Posts: 85
Thanks: 10
Thanked 0 Times in 0 Posts
|
|
Thank you very much Martin. Its working now.
Could you please give some hint how can I ignore the extension in the Name element.
and group the name element.
for example:
Code:
<Display>
<Results>
<Result>
<ModifyDate>20110412</ModifyDate>
<ModifyTime>161144</ModifyTime>
<Name>Test.doc</Name>
</Result>
<Result>
<ModifyDate>20110412</ModifyDate>
<ModifyTime>161211</ModifyTime>
<Name>Test.pdf</Name>
</Result>
<Result>
<ModifyDate>20110310</ModifyDate>
<ModifyTime>140502</ModifyTime>
<Name>Usert.doc</Name>
</Result>
</Results>
</Display>
In the Name element one is 'Test.doc' and other is 'Test.pdf' how can group based on just word 'Test'
Any Idea ?
Thanks Again
-Nelly
|
|

April 20th, 2011, 12:25 PM
|
|
Friend of Wrox
|
|
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
|
|
As long as you know there is only one dot change the key use attribute to
use="substring-before(Name, '.')"
and of course anywhere where you then use the key you need to make sure you change any
Name
expression to
substring-before(Name, '.')
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
|
|
The Following User Says Thank You to Martin Honnen For This Useful Post:
|
|
|

April 21st, 2011, 09:53 AM
|
|
Authorized User
|
|
Join Date: Apr 2008
Posts: 85
Thanks: 10
Thanked 0 Times in 0 Posts
|
|
Thanks again Martin....All is working fine.
Here is the final working XSLT for others who might need:
<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="Results-by-Name" match="SearchResult" use="substring-before(Name, '.')"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Results">
<xsl:copy>
<xsl:apply-templates select="Result[generate-id() = generate-id(key('Results-by-Name', substring-before(OTName, '.'))[1])]" mode="group"/>
</xsl:copy>
</xsl:template>
<xsl:template match="SearchResult" mode="group">
<xsl:for-each select="key('Results-by-Name', substring-before(Name, '.'))">
<xsl:sort select="ModifyDate + ModifyTime" data-type="number" order="descending"/>
<xsl:if test="position() = 1">
<xsl:apply-templates select="."/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Regards
-Nelly
|
|

April 28th, 2011, 10:25 AM
|
|
Authorized User
|
|
Join Date: Apr 2008
Posts: 85
Thanks: 10
Thanked 0 Times in 0 Posts
|
|
Hi Martin,
Could you please give some hint about the below problem.
if in the name element suppose only values are 'Test' and 'Test.doc'
then what do use in the key 'use'. because if I use like this use="substring-before(Name, '.') then
it is working only for the name element which has '.' and for other it is ignoring and I am getting those
record as well.
Could you please give idea how to resolve this.
Thanks Again
-Nelly
|
|

April 28th, 2011, 10:42 AM
|
|
Friend of Wrox
|
|
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
|
|
Does
Code:
use="substring-before(concat(Name, '.'), '.')"
work for that case. In the case of "Test" the concat produces "Test." and the substring-before "Test", in the case of "Test.doc" the concat produces "Test.doc." and the substring-before produces "Test". So that way both elements would have the same key.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
|
|

April 28th, 2011, 11:19 AM
|
|
Authorized User
|
|
Join Date: Apr 2008
Posts: 85
Thanks: 10
Thanked 0 Times in 0 Posts
|
|
Thanks for your reply.
What I meant is for example below is the XML:
Code:
<Display>
<Results>
<Result>
<ModifyDate>20110412</ModifyDate>
<ModifyTime>161144</ModifyTime>
<Name>Test</Name>
</Result>
<Result>
<ModifyDate>20110412</ModifyDate>
<ModifyTime>161211</ModifyTime>
<Name>Test.pdf</Name>
</Result>
<Result>
<ModifyDate>20110310</ModifyDate>
<ModifyTime>140502</ModifyTime>
<Name>User.doc</Name>
</Result>
</Results>
</Display>
and XSLT is :
Code:
<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="Results-by-Name" match="Result" use="substring-before(concat(Name, '.'), '.')"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Results">
<xsl:copy>
<xsl:apply-templates select="Result[generate-id() = generate-id(key('Results-by-Name', substring-before(concat(Name, '.'), '.'))[1])]" mode="group"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Result" mode="group">
<xsl:for-each select="key('Results-by-Name', substring-before(concat(Name, '.'), '.'))">
<xsl:sort select="ModifyDate" data-type="number" order="descending"/>
<xsl:sort select="ModifyTime" data-type="number" order="descending"/>
<xsl:if test="position() = 1">
<xsl:apply-templates select="."/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
and the output XML I wanted based on the Name,Modify and Time element is:
Code:
<Display>
<Results>
<Result>
<ModifyDate>20110412</ModifyDate>
<ModifyTime>161144</ModifyTime>
<Name>Test</Name>
</Result>
<Result>
<ModifyDate>20110310</ModifyDate>
<ModifyTime>140502</ModifyTime>
<Name>User.doc</Name>
</Result>
</Results>
</Display>
It should only compare the text before the '.'
In the key if I use 'substring-before(Name,'.')' or ''substring-before(concat(Name, '.'), '.')'
does not make any difference.
Kindly advice.
Thanks
-Nelly
|
|

April 28th, 2011, 11:29 AM
|
|
Friend of Wrox
|
|
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
|
|
I don't understand what you want to achieve. When I run your latest samples with an XSLT 1.0 processor like Saxon 6.5.5. I get the following result:
Code:
<Display>
<Results>
<Result>
<ModifyDate>20110412</ModifyDate>
<ModifyTime>161211</ModifyTime>
<Name>Test.pdf</Name>
</Result>
<Result>
<ModifyDate>20110310</ModifyDate>
<ModifyTime>140502</ModifyTime>
<Name>User.doc</Name>
</Result>
</Results>
</Display>
So the grouping has happened correctly. The latest element in the first group with the key "Test" is the one with <ModifyTime>161211</ModifyTime>, not the one with <ModifyTime>161144</ModifyTime>. If you don't want the latest element then change the sort order to ascending.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
|
|

April 28th, 2011, 11:41 AM
|
 |
Friend of Wrox
|
|
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
|
|
I think you simply need to add another template to handle the outputting of the Name element:
Code:
<xsl:template match="Result/Name">
<Name><xsl:value-of select="substring-before(concat(.,'.'),'.')"/></Name>
</xsl:template>
|
|

April 30th, 2011, 06:42 AM
|
|
Authorized User
|
|
Join Date: Apr 2008
Posts: 85
Thanks: 10
Thanked 0 Times in 0 Posts
|
|
Hi Sam and Martin,
Thank you ver much for your help and replies.
I have found the problem in the XML. If the name element like this below :
<Name>
Test
</Name>
in the XML :
Code:
<Display>
<Results>
<Result>
<ModifyDate>20110412</ModifyDate>
<ModifyTime>161144</ModifyTime>
<Name>
Test
</Name>
</Result>
<Result>
<ModifyDate>20110412</ModifyDate>
<ModifyTime>161211</ModifyTime>
<Name>
Test.xml
</Name>
</Result>
<Result>
<ModifyDate>20110310</ModifyDate>
<ModifyTime>140502</ModifyTime>
<Name>
User.doc
</Name>
</Result>
</Results>
</Display>
this its is return both 'Test' and 'Test.XML' and if the Name element like below:
<Name>Test</Name> in the XML.
Code:
<Display>
<Results>
<Result>
<ModifyDate>20110412</ModifyDate>
<ModifyTime>161144</ModifyTime>
<Name>Test</Name>
</Result>
<Result>
<ModifyDate>20110412</ModifyDate>
<ModifyTime>161211</ModifyTime>
<Name>Test.xml</Name>
</Result>
<Result>
<ModifyDate>20110310</ModifyDate>
<ModifyTime>140502</ModifyTime>
<Name>User.doc</Name>
</Result>
</Results>
</Display>
then it return correct result 'Test.xml'. I think the issue is with the white space.
How can I ignore the white space ?
Thanks Again
-Nelly
|
|
 |