Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

select the group of rows based on the three XML fields and with these 1

Status
Not open for further replies.

ccpuser

Programmer
Oct 21, 2010
2
US
I would like to group based on fields of row element (combination of StackNumber,BlockNumber and LocationCode) and select only higher BookVersion (BookVersion) based rows in particular group(combination of StackNumber,BlockNumber and LocationCode) and also to select the rows of DeliveryMode with the value as TRANSIT.

Here is the input document

<?xml version="1.0"?>
<Output>
<row>
<StackNumber>19</StackNumber>
<BlockNumber>61001</BlockNumber>
<DeliveryMode>TRANSIT</DeliveryMode>
<LocationCode>MON</LocationCode>
<BookVersion>03</BookVersion>
<StoreNumber>1010</StoreNumber>

</row>
<row>
<StackNumber>20</StackNumber>
<BlockNumber>61001</BlockNumber>
<DeliveryMode>TRANSIT</DeliveryMode>
<LocationCode>MON</LocationCode>
<BookVersion>01</BookVersion>
<StoreNumber>1011</StoreNumber>
</row>
<row>
<StackNumber>20</StackNumber>
<BlockNumber>61001</BlockNumber>
<DeliveryMode>TRANSIT</DeliveryMode>
<LocationCode>MON</LocationCode>
<BookVersion>02</BookVersion>
<StoreNumber>1013</StoreNumber>
</row>
<row>
<StackNumber>21</StackNumber>
<BlockNumber>61001</BlockNumber>
<DeliveryMode>RECVD</DeliveryMode>
<LocationCode>MON</LocationCode>
<BookVersion>03</BookVersion>
<StoreNumber>1022</StoreNumber>
</row>
<row>
<StackNumber>21</StackNumber>
<BlockNumber>61001</BlockNumber>
<DeliveryMode>TRANSIT</DeliveryMode>
<LocationCode>MON</LocationCode>
<BookVersion>03</BookVersion>
<StoreNumber>1022</StoreNumber>
</row>
<row>
<StackNumber>22</StackNumber>
<BlockNumber>15098</BlockNumber>
<DeliveryMode>TRANSIT</DeliveryMode>
<LocationCode>MON</LocationCode>
<BookVersion>01</BookVersion>
<StoreNumber>1010</StoreNumber>
</row>
<row>
<StackNumber>22</StackNumber>
<BlockNumber>22456</BlockNumber>
<DeliveryMode>TRANSIT</DeliveryMode>
<LocationCode>MON</LocationCode>
<BookVersion>02</BookVersion>
<StoreNumber>1011</StoreNumber>
</row>
<row>
<StackNumber>22</StackNumber>
<BlockNumber>22456</BlockNumber>
<DeliveryMode>TRANSIT</DeliveryMode>
<LocationCode>MON</LocationCode>
<BookVersion>03</BookVersion>
<StoreNumber>1012</StoreNumber>
</row>
<row>
<StackNumber>22</StackNumber>
<BlockNumber>22456</BlockNumber>
<DeliveryMode>RECVD</DeliveryMode>
<LocationCode>MON</LocationCode>
<BookVersion>02</BookVersion>
<StoreNumber>1021</StoreNumber>
</row>
</Output>
XSL (using saxon 9 parser) that I wrote:

<xsl:stylesheet version="1.0" xmlns:xsl="
<xsl:eek:utput method="xml" indent="yes"/>

<xsl:key name="transitGroup" match="row" use="concat(StackNumber,BlockNumber,LocationCode)"/>

<xsl:template match="/">
<Output>
<xsl:for-each select="//row[generate-id(.) = generate-id(key('transitGroup',concat(StackNumber,BlockNumb er,LocationCode))[1])]">
<xsl:variable name="BookVersion" select="key('transitGroup',concat(StackNumber,Bloc kNumber,LocationCode))/BookVersion"/>
<xsl:if test="DeliveryMode = 'TRANSIT'">
<row>
<StackNumber>
<xsl:value-of select="StackNumber"/>
</StackNumber>
<BlockNumber>
<xsl:value-of select="BlockNumber"/>
</BlockNumber>
<LocationCode>
<xsl:value-of select="LocationCode"/>
</LocationCode>
<StoreNumber>
<xsl:value-of select="StoreNumber"/>
</StoreNumber>

<xsl:for-each select="$BookVersion">

<xsl:sort select="." data-type="number" order="descending"/>

<xsl:if test="position()=1">

<BookVersion>
<xsl:value-of select="."/>
</BookVersion>
</xsl:if>
</xsl:for-each>
</row>
</xsl:if>
</xsl:for-each>
</Output>
</xsl:template>
</xsl:stylesheet>


I wrote this above one but can't figure out to select correct store number based on greater value based element 'BookVersion' in each group.

example group must be printed like this .

<row>
<StackNumber>20</StackNumber>
<BlockNumber>61001</BlockNumber>
<LocationCode>MON</LocationCode>
<StoreNumber>1013</StoreNumber>
<BookVersion>02</BookVersion>
</row>

I'm getting wrong store number here for a particular selected group. I'm struck to proceed further here, I will appreciate if some body can lead me the way to write correct it in this XSL.
 
[0] I think this will be clearer with each construction reflecting a special line of thinking to get to the result.
[tt]
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="[ignore][/ignore]">
<xsl:eek:utput method="xml" indent="yes" encoding="utf-8" />
<xsl:key name="transitGroup" match="row[DeliveryMode='TRANSIT']" use="concat(StackNumber,BlockNumber,LocationCode)"/>

<xsl:template match="/">
<xsl:apply-templates select="Output" />
</xsl:template>

<xsl:template match="Output">
<Output>
<xsl:apply-templates select="row[DeliveryMode='TRANSIT']" mode="special"/>
</Output>
</xsl:template>

<xsl:template match="row[DeliveryMode='TRANSIT']" mode="special">
<xsl:if test="generate-id(.)=generate-id(key('transitGroup', concat(StackNumber,BlockNumber,LocationCode))[1])">
<xsl:for-each select="key('transitGroup', concat(StackNumber,BlockNumber,LocationCode))">
<xsl:sort select="BookVersion" data-type="number" order="descending" />
<xsl:choose>
<xsl:when test="position() = 1">
<xsl:call-template name="display" />
</xsl:when>
<xsl:eek:therwise>
<!-- do nothing -->
</xsl:eek:therwise>
</xsl:choose>
</xsl:for-each>
</xsl:if>
</xsl:template>

<xsl:template name="display">
<row>
<StackNumber>
<xsl:value-of select="StackNumber"/>
</StackNumber>
<BlockNumber>
<xsl:value-of select="BlockNumber"/>
</BlockNumber>
<LocationCode>
<xsl:value-of select="LocationCode"/>
</LocationCode>
<StoreNumber>
<xsl:value-of select="StoreNumber"/>
</StoreNumber>
<BookVersion>
<xsl:value-of select="BookVersion" />
</BookVersion>
</row>
</xsl:template>

</xsl:stylesheet>
[/tt]
[1] The problem with your script, apart from being loose in the construction at places, is that the BookVersion suddenly pop up like a block-apart...

[2] Just a side-note. If you think you've got adequate help, maybe you can put up a note at the "other" forum so that the conduct is more professional. But I won't insist!
 
Another solution for this problem based on on XSL version 2.0 feature:

<?xml version="1.0" encoding="US-ASCII"?>
<xsl:stylesheet xmlns:xsl=" xmlns:xsd=" exclude-result-prefixes="xsd"
version="2.0">

<xsl:eek:utput indent="yes"/>

<xsl:template match="/">
<Output>
<xsl:for-each-group select="*/row[DeliveryMode='TRANSIT']"
group-by="concat(StackNumber,'&#xd;',
BlockNumber,'&#xd;',LocationCode)">
<xsl:for-each select="current-group()
[xsd:decimal(BookVersion)=
max(current-group()/BookVersion/xsd:decimal(.))]
[1]">
<row>
<xsl:copy-of select="* except DeliveryMode"/>
</row>
</xsl:for-each>
</xsl:for-each-group>
</Output>
</xsl:template>

</xsl:stylesheet>
 
xslt 2.0 solutions are sure possible and thanks for the post-back of one.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top