Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
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
 
Old April 19th, 2011, 12:55 PM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

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
 
Old April 20th, 2011, 12:18 PM
Authorized User
 
Join Date: Apr 2008
Posts: 85
Thanks: 10
Thanked 0 Times in 0 Posts
Default

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
 
Old April 20th, 2011, 12:25 PM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

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:
nelly78 (April 21st, 2011)
 
Old April 21st, 2011, 09:53 AM
Authorized User
 
Join Date: Apr 2008
Posts: 85
Thanks: 10
Thanked 0 Times in 0 Posts
Default

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
 
Old April 28th, 2011, 10:25 AM
Authorized User
 
Join Date: Apr 2008
Posts: 85
Thanks: 10
Thanked 0 Times in 0 Posts
Default

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
 
Old April 28th, 2011, 10:42 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

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
 
Old April 28th, 2011, 11:19 AM
Authorized User
 
Join Date: Apr 2008
Posts: 85
Thanks: 10
Thanked 0 Times in 0 Posts
Default

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
 
Old April 28th, 2011, 11:29 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

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
 
Old April 28th, 2011, 11:41 AM
samjudson's Avatar
Friend of Wrox
 
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

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>
__________________
/- Sam Judson : Wrox Technical Editor -/

Think before you post: What have you tried?
 
Old April 30th, 2011, 06:42 AM
Authorized User
 
Join Date: Apr 2008
Posts: 85
Thanks: 10
Thanked 0 Times in 0 Posts
Default

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





Similar Threads
Thread Thread Starter Forum Replies Last Post
Split xml file with result document and javax.xml.transform.Transformer. nisargmca XSLT 3 January 12th, 2010 06:26 AM
After recreating database on my Host Server, do I .... Ali Ezz BOOK: Beginning ASP.NET 3.5 : in C# and VB BOOK ISBN: 978-0-470-18759-3 1 January 3rd, 2010 06:58 AM
VB.net, adding XML data to an existing XML file saikoboarder XML 11 April 17th, 2008 04:19 PM
E-mailing InfoPath Forms & Recreating XML Data... bburnsid Infopath 0 January 22nd, 2007 05:13 PM
recreating propertygrid using listview ken_kapchan BOOK: Professional C#, 2nd and 3rd Editions 0 March 22nd, 2004 05:48 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.