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 March 9th, 2016, 07:07 AM
Authorized User
 
Join Date: Nov 2015
Posts: 12
Thanks: 4
Thanked 0 Times in 0 Posts
Default Group XML message based on 3 keys

Input XML

<Positions>
<Position>
<cust_HireType/>
<location>London</location>
<department/>
<cust_TCCID/>
<cust_RegulatedRole/>
<code>001000090</code>
<effectiveStatus>A</effectiveStatus>
<costCenter>18845-3761</costCenter>
</Position>
<Position>
<cust_HireType>Inv</cust_HireType>
<location>London</location>
<department>25092089</department>
<cust_TCCID/>
<cust_RegulatedRole>no</cust_RegulatedRole>
<code>001000090</code>
<effectiveStatus>A</effectiveStatus>
<costCenter>18845-3761</costCenter>
</Position>
<Position>
<cust_HireType>Inv</cust_HireType>
<location>London</location>
<department>25092089</department>
<cust_TCCID/>
<cust_RegulatedRole>no</cust_RegulatedRole>
<code>001000090</code>
<effectiveStatus>A</effectiveStatus>
<costCenter>18845-3761</costCenter>
</Position>
<Position>
<cust_HireType>Inv</cust_HireType>
<location>Nigeria</location>
<department>25092089</department>
<cust_TCCID/>
<cust_RegulatedRole>no</cust_RegulatedRole>
<code>001000078</code>
<effectiveStatus>A</effectiveStatus>
<costCenter>18845-3761</costCenter>
</Position>
<Position>
<cust_HireType>Inv</cust_HireType>
<location>Paris</location>
<department>25092089</department>
<cust_TCCID/>
<cust_RegulatedRole>no</cust_RegulatedRole>
<code>001000067</code>
<effectiveStatus>A</effectiveStatus>
<costCenter>18845-3761</costCenter>
</Position>
</Positions>


Output XML:

<Positions>
<Position>
<cust_HireType/>
<location>London</location>
<department/>
<cust_TCCID/>
<cust_RegulatedRole/>
<code>001000090</code>
<effectiveStatus>A</effectiveStatus>
<costCenter>18845-3761</costCenter>
<NOC>2</NOC>
</Position>
<Position>
<cust_HireType>Inv</cust_HireType>
<location>London</location>
<department>25092089</department>
<cust_TCCID/>
<cust_RegulatedRole>no</cust_RegulatedRole>
<code>001000090</code>
<effectiveStatus>A</effectiveStatus>
<costCenter>18845-3761</costCenter>
<NOC>0</NOC>
</Position>
<Position>
<cust_HireType>Inv</cust_HireType>
<location>London</location>
<department>25092089</department>
<cust_TCCID/>
<cust_RegulatedRole>no</cust_RegulatedRole>
<code>001000090</code>
<effectiveStatus>A</effectiveStatus>
<costCenter>18845-3761</costCenter>
<NOC>0</NOC>
</Position>
<NOP>3</NOP>
</Positions>

Requirement: Need to group XML based on 3 key values which is location,code and cost center in the input file. The output should have all the fields as the input XML with 1 extra tag added in the first position tag with value as total number of similar positions -1 and the other second and third position with value as 0. And an additional tag with total number of position tags with similar keys which is in this case is 3.
 
Old March 9th, 2016, 07:19 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

This looks like a pretty standard grouping question. You haven't made it clear whether you are using XSLT 1.0 or 2.0 (the solutions will be very different), and you haven't given any clues about what you have tried or investigated, so we don't really know where you got stuck. If you're using XSLT 2.0, use xsl:for-each-group; if you're forced to use 1.0, use Muenchian Grouping, which you will find in the index of your favourite Wrox XSLT book.

Neither XSLT 1.0 nor 2.0 offer any special way of handling composite grouping keys, you will need to combine the keys into a single string using string concatenation.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
 
Old March 9th, 2016, 08:45 AM
Authorized User
 
Join Date: Nov 2015
Posts: 12
Thanks: 4
Thanked 0 Times in 0 Posts
Default

Hi,
I was trying to do this with single key "location" first but unable to achieve the requirement.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" indent="yes" />
<xsl:template match="/">

<Positions>

<xsl:for-each select="Positions/Position">
<xsl:variable name="location1">
<xsl:value-of select="location"/>
</xsl:variable>




<Position>
<cust_HireType>
<xsl:value-of select="cust_HireType"/>
</cust_HireType>
<location>
<xsl:call-template name="XXX">
<xsl:with-param name="location1" select="$location1"/>
</xsl:call-template>

</location>
<department>
<xsl:value-of select="department"/>
</department>
<cust_TCCID>
<xsl:value-of select="cust_TCCID"/>
</cust_TCCID>
<cust_RegulatedRole>
<xsl:value-of select="cust_RegulatedRole"/>
</cust_RegulatedRole>
<code>
<xsl:value-of select="code"/>
</code>
<effectiveStatus>
<xsl:value-of select="effectiveStatus"/>
</effectiveStatus>





</Position>
</xsl:for-each>
</Positions>
</xsl:template>

<xsl:template name="XXX">
<xsl:param name="location1"/>

<xsl:for-each select="Positions/Position/location">
<xsl:choose>
<xsl:when test="$location1=location">
<xsl:value-of select="location"/>
</xsl:when>
</xsl:choose>


</xsl:for-each>
</xsl:template>



</xsl:stylesheet>

I am using XSLT 2.0 but unable to achieve it.
 
Old March 9th, 2016, 10:24 AM
samjudson's Avatar
Friend of Wrox
 
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

You probably want to use the xsl:for-each-group instruction, something like this:

Code:
<xsl:for-each-group select="Position" group-by="concat(location, '|', code, '|', costCenter)">
...
</xsl:for-each-group>
Then inside this you would want to use the current-group() sequence to output the first element, with the count() - 1, and then the rest with the count = 0.
__________________
/- Sam Judson : Wrox Technical Editor -/

Think before you post: What have you tried?
The Following User Says Thank You to samjudson For This Useful Post:
Lipsita (March 9th, 2016)
 
Old March 9th, 2016, 10:31 AM
samjudson's Avatar
Friend of Wrox
 
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

Oh, and final count would be something using the count() and distinct-values() functions.
__________________
/- Sam Judson : Wrox Technical Editor -/

Think before you post: What have you tried?
The Following User Says Thank You to samjudson For This Useful Post:
Lipsita (March 9th, 2016)
 
Old March 9th, 2016, 01:33 PM
Authorized User
 
Join Date: Nov 2015
Posts: 12
Thanks: 4
Thanked 0 Times in 0 Posts
Default

Hi,

Thanks for the response. I tried using the for each group function but unable to achieve the requirement.Please correct me as i am a beginner in XSLT and also elaborate on where to use the count and distinct value functions.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" indent="yes" />
<xsl:template match="/">

<Positions>

<xsl:for-each-group select="Position" group-by="concat(location, '|', code, '|', costCenter)">



<Position>

<cust_HireType>
<xsl:value-of select="cust_HireType"/>
</cust_HireType>
<location>
<xsl:value-of select="location"/>

</location>
<department>
<xsl:value-of select="department"/>
</department>
<cust_TCCID>
<xsl:value-of select="cust_TCCID"/>
</cust_TCCID>
<cust_RegulatedRole>
<xsl:value-of select="cust_RegulatedRole"/>
</cust_RegulatedRole>
<code>
<xsl:value-of select="code"/>
</code>
<effectiveStatus>
<xsl:value-of select="effectiveStatus"/>
</effectiveStatus>




</Position>
</xsl:for-each-group>
</Positions>

</xsl:template>


</xsl:stylesheet>
 
Old March 10th, 2016, 05:12 AM
samjudson's Avatar
Friend of Wrox
 
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

Inside the xsl:for-each-group you have access to a set, called current-group() that returns you all the nodes in that group.

So you can the perform a xsl:for-each over that group:

Code:
<xsl:for-each select="current-group()">
<Position>
  <xsl:apply-templates/> <!-- this defaults to processing all the child nodes) -->
</Position>
</xsl:for-each>
To add the NOC element you would then need to work out if you are in the first element or not, usually using the position() function (if it is equal to 1 you are in the first element).

You could do this using an xsl:choose with an xsl:when and an xsl:otherwise, or you could use xquery:

Code:
<NOC><xsl:value-of select="if(position()=1) then count(current-group()) - 1 else 0"/></NOC>
The function for getting the complete count would be:

Code:
count(distinct-values(Position/concat(location, '|', code, '|', costCenter)))
__________________
/- Sam Judson : Wrox Technical Editor -/

Think before you post: What have you tried?





Similar Threads
Thread Thread Starter Forum Replies Last Post
Transform Attribute based xml to element based xml pallone XSLT 6 February 2nd, 2016 07:59 AM
Help me to select group based on maximum value CCPuser XSLT 3 August 31st, 2012 03:09 PM
select the group of rows based on the three XML fields and with these conditions. CCPuser XSLT 3 October 22nd, 2010 09:11 AM
select the group of rows based on the three XML fields and with conditions. CCPuser BOOK: XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition ISBN: 978-0-470-19274-0 1 October 22nd, 2010 09:06 AM
group data in table based on a value praveenanekalmat XSLT 2 January 7th, 2009 03:09 AM





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