Reputation: 2391
I kind of need to create "group of groups" using XSLT.
Below are my XML and XSL files. I used this SO link to apply Muenchian grouping. I have tried to shorten the file and show only the required elements that represents the problem.
XML FILE
<IO_SearchShoppingFilesResult xmlns="http://schemas.datacontract.org/2004/07/Trevoo.WS.IO.Shopping" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ShoppingFiles
xmlns:a="http://schemas.datacontract.org/2004/07/Trevoo.WS.Entities.Shopping"
xmlns:b="http://schemas.datacontract.org/2004/07/Trevoo.WS.Entities.Air">
<a:T_ShoppingFile>
....
<b:T_AirBookingItem>
...
<a:LocalPaxType>ADT</a:LocalPaxType>
...
</b:T_AirBookingItem>
<b:T_AirBookingItem>
...
<a:LocalPaxType>CHD</a:LocalPaxType>
...
</b:T_AirBookingItem>
<b:T_AirBookingItem>
...
<a:LocalPaxType>INF</a:LocalPaxType>
...
</b:T_AirBookingItem>
...
</a:T_ShoppingFile>
<a:T_ShoppingFile>
....
<b:T_AirBookingItem>
...
<a:LocalPaxType>ADT</a:LocalPaxType>
...
</b:T_AirBookingItem>
...
</a:T_ShoppingFile>
</ShoppingFiles>
</IO_SearchShoppingFilesResult>
XSL FILE
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:res="http://schemas.datacontract.org/2004/07/Trevoo.WS.IO.Shopping"
xmlns:a="http://schemas.datacontract.org/2004/07/Trevoo.WS.Entities.Shopping"
xmlns:b="http://schemas.datacontract.org/2004/07/Trevoo.WS.Entities.Air"
xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
xmlns:bb="http://schemas.datacontract.org/2004/07/Trevoo.WS.Entities.Shopping.Views">
<xsl:output method="xml" indent="yes" />
<xsl:key name="travelerGroup"
match="res:IO_SearchShoppingFilesResult/res:ShoppingFiles/a:T_ShoppingFile[position()=1]/a:AirBookings/b:T_AirBooking/b:BookingItems/b:T_AirBookingItem"
use="b:PaxReference/a:LocalPaxType" />
<xsl:template match="/">
<xsl:element name="PNRViewRS">
<xsl:apply-templates
select="res:IO_SearchShoppingFilesResult/res:ShoppingFiles" />
</xsl:element>
</xsl:template>
<xsl:template match="res:ShoppingFiles">
<!-- For FareGroup, Traveler, Telephone, EmailAddress -->
<xsl:apply-templates select="a:T_ShoppingFile" />
...
</xsl:template>
<xsl:template match="a:T_ShoppingFile">
...
<xsl:apply-templates
select="a:AirBookings/b:T_AirBooking/b:BookingItems/b:T_AirBookingItem[generate-id() = generate-id(key('travelerGroup', b:PaxReference/a:LocalPaxType)[1])]" />
...
</xsl:template>
...
<xsl:template match="b:T_AirBookingItem">
...
<!-- Line 1 -->
<xsl:value-of
select="count(key('travelerGroup', b:PaxReference/a:LocalPaxType))" />
...
</xsl:template>
As one can see, I have applied key
on <b:T_AirBookingItem>
. And multiple <b:T_AirBookingItem>
are present in multiple <a:T_ShoppingFile>
.
Now, I want to handle each <a:T_ShoppingFile>
separately and then apply grouping on all the <b:T_AirBookingItem>
present in it. What happens here in this code is that all the <b:T_AirBookingItem>
of all the <a:T_ShoppingFile>
are grouped all together at a time.
Line 1 shows one of the result of this transformation. It should show total number of <b:T_AirBookingItem>
of a particular <a:LocalPaxType>
(say ADT) for a single <a:T_ShoppingFile>
. However, it considers all the <b:T_AirBookingItem>
in the whole of XML instead.
So where I should get "1" number of ADTs, I am getting "2".
How do I deal with it?
Upvotes: 0
Views: 300
Reputation: 70648
It sound like you want to make use of a compound key, consisting of more than one element. In this case you are gouping by a:T_ShoppingFile and a:LocalPaxType, so you probably need something like this
<xsl:key
name="item"
match="b:T_AirBookingItem"
use="concat(generate-id(..) , '|', a:LocalPaxType)" />
Then, for each a:T_ShoppingFile to get the unique a:LocalPaxType records, you just do this
<xsl:apply-templates
select="b:T_AirBookingItem[generate-id()
= generate-id(key('item', concat(generate-id(..) , '|', a:LocalPaxType))[1])]" />
Here is the full XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:res="http://schemas.datacontract.org/2004/07/Trevoo.WS.IO.Shopping" xmlns:a="http://schemas.datacontract.org/2004/07/Trevoo.WS.Entities.Shopping" xmlns:b="http://schemas.datacontract.org/2004/07/Trevoo.WS.Entities.Air" xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:bb="http://schemas.datacontract.org/2004/07/Trevoo.WS.Entities.Shopping.Views" exclude-result-prefixes="res a b c bb">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="item" match="b:T_AirBookingItem" use="concat(generate-id(..) , '|', a:LocalPaxType)"/>
<xsl:template match="/">
<xsl:apply-templates select="//a:T_ShoppingFile"/>
</xsl:template>
<xsl:template match="a:T_ShoppingFile">
<file number="{position()}">
<xsl:apply-templates select="b:T_AirBookingItem[generate-id() = generate-id(key('item', concat(generate-id(..) , '|', a:LocalPaxType))[1])]"/>
</file>
</xsl:template>
<xsl:template match="b:T_AirBookingItem">
<result>
<xsl:value-of select="concat(a:LocalPaxType, ' * ', count(key('item', concat(generate-id(..) , '|', a:LocalPaxType))), ' ')"/>
</result>
</xsl:template>
</xsl:stylesheet>
When applied to your XML, the following is output
<file number="1">
<result>ADT * 1</result>
<result>CHD * 1</result>
<result>INF * 1</result>
</file>
<file number="2">
<result>ADT * 1</result>
</file>
Obviously, this shows results for all a:T_ShoppingFile and a:LocalPaxType. If you wanted to restrict to a particular a:LocalPaxType you could do something like this (although you would probably want to parameterise the value, rather than hard-code ADT
<xsl:template match="a:T_ShoppingFile">
<file number="{position()}">
<xsl:value-of select="count(key('item', concat(generate-id() , '|', 'ADT')))" />
</file>
</xsl:template>
Upvotes: 1