XML Editor
Sign up for a WebBoard account Sign Up Keyword Search Search More Options... Options
Chat Rooms Chat Help Help News News Log in to WebBoard Log in Not Logged in
Show tree view Topic
Topic Page 1 2 3 4 5 6 7 8 9 Go to previous topicPrev TopicGo to next topicNext Topic
Postnext
Sameer ShadabSubject: XSLT Requirement - something like duplicate elements
Author: Sameer Shadab
Date: 30 Jun 2005 09:52 AM
Hi friends,
I have a requirement to be done using XSLT, was wondering if anyone can help me out,


<Shipment>
<ShipmentInfo>
<SegmentIdentifier>*BA</SegmentIdentifier>
<ShipTo>0004100357</ShipTo>
<PackageCount>2</PackageCount>
<ShpmntWeight>30</CompanyName>
<UOM>KG</UOM>
</ShipmentInfo>

<ShipmentInfo>
<SegmentIdentifier>*BA</SegmentIdentifier>
<ShipTo>0004100357</ShipTo>
<PackageCount>3</PackageCount>
<ShpmntWeight>25</CompanyName>
<UOM>KG</UOM>
</ShipmentInfo>

<ShipmentInfo>
<SegmentIdentifier>*BA</SegmentIdentifier>
<ShipTo>0004100357</ShipTo>
<PackageCount>2</PackageCount>
<ShpmntWeight>20</CompanyName>
<UOM>KG</UOM>
</ShipmentInfo>

<ShipmentInfo>
<SegmentIdentifier>*BA</SegmentIdentifier>
<ShipTo>0004100300</ShipTo>
<PackageCount>2</PackageCount>
<ShpmntWeight>30</CompanyName>
<UOM>KG</UOM>
</ShipmentInfo>

</Shipment>

The requirement of the xslt is to convert the above xml to a flat-file structure. The output for the above example should be flat file with value as below,

*BA00041003577 75 KG
*BA00041003002 30 KG

I have mentioned the lengths of the fields below,
Length of SegmentIdentifier field - 3
Length of ShipTo field - 10
Length of PackageCount field - 3
Length of ShpmntWeight field - 4
Length of UOM field - 2

So based on these lengths in the flatfile o/p shown above, the first 3 characters represent 'SegmentIdentifier', next 10 represent 'ShipTo' etc. If the field is of lesser length, then they should be replaced by spaces.

Take the first line of the flatfile output,

*BA00041003577 75 KG

This is basically arrived using the following condition, we should check for the all the ShipmentInfo segment having same 'ShipTo' field and then once that is identified, we should basically sum the corresponding PackageCount (2+3+2=7) and ShpmntWeight (30+25+20=70) and append it to the flatfile.

But if the ShipTo is unique then each segment should have a separate line (as seen in the second line of the flat-file),

*BA00041003002 30 KG

I hope i have written my requirement clearly, if i get some help on this, i can build upon this xslt and go ahead coding the rest.

thanks
Sameer

Postnext
Ivan PedruzziSubject: XSLT Requirement - something like duplicate elements
Author: Ivan Pedruzzi
Date: 01 Jul 2005 12:14 AM
Hi Sameer

I am preseting 2 solutions

-----------------------------------------------------------
Using XSLT 1

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

<!-- Build a key to group ShipmentInfo by ShipTo -->
<xsl:key name="ShipTo" match="Shipment/ShipmentInfo" use="ShipTo"/>

<xsl:template match="/">

<!-- iterate on each group -->
<xsl:for-each select="Shipment/ShipmentInfo[generate-id(.) = generate-id(key('ShipTo', ShipTo)[1]) ]">

<xsl:variable name="group" select="key('ShipTo', ShipTo)"/>

<xsl:variable name="SegmentIdentifier">
<xsl:call-template name="padd-value">
<xsl:with-param name="value" select="SegmentIdentifier"/>
<xsl:with-param name="size" select="3"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="ShipTo">
<xsl:call-template name="padd-value">
<xsl:with-param name="value" select="ShipTo"/>
<xsl:with-param name="size" select="10"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="PackageCount">
<xsl:call-template name="padd-value">
<xsl:with-param name="value" select="sum($group/PackageCount)"/>
<xsl:with-param name="size" select="3"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="ShpmntWeight">
<xsl:call-template name="padd-value">
<xsl:with-param name="value" select="sum($group/ShpmntWeight)"/>
<xsl:with-param name="size" select="4"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="UOM">
<xsl:call-template name="padd-value">
<xsl:with-param name="value" select="UOM"/>
<xsl:with-param name="size" select="2"/>
</xsl:call-template>
</xsl:variable>

<xsl:value-of select="concat($SegmentIdentifier, $ShipTo, $PackageCount, $ShpmntWeight, $UOM)"/><xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>


<xsl:template name="padd-value">
<xsl:param name="value"/>
<xsl:param name="size"/>
<xsl:param name="padding_char" select="' '"/>
<xsl:value-of select="$value"/>
<xsl:call-template name="padding">
<xsl:with-param name="value" select="$value"/>
<xsl:with-param name="size" select="$size - 1"/>
</xsl:call-template>
</xsl:template>

<xsl:template name="padding">
<xsl:param name="value"/>
<xsl:param name="size"/>
<xsl:param name="padding_char" select="' '"/>
<xsl:if test="$size &gt; string-length($value)"><xsl:value-of select="$padding_char"/>
<xsl:call-template name="padding">
<xsl:with-param name="value" select="$value"/>
<xsl:with-param name="size" select="$size - 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>

</xsl:stylesheet>

--------------------------------------------------------------------
Using XSLT 2
Here you can see three great XSLT 2 features
for-each-group
XPath User defined functions
operator 'to'

<?xml version='1.0'?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:local="http://www.acme.org"
xmlns:fn="http://www.w3.org/2005/04/xpath-functions">

<xsl:template match="/">
<xsl:for-each-group select="Shipment/ShipmentInfo" group-by="ShipTo">
<xsl:value-of select="concat(
local:padding(SegmentIdentifier, 3),
local:padding(ShipTo, 10),
local:padding(sum(current-group()/PackageCount), 3),
local:padding(sum(current-group()/ShpmntWeight), 4),
local:padding(UOM, 2))"/><xsl:text>
</xsl:text>
</xsl:for-each-group>
</xsl:template>

<xsl:function name="local:padding">
<xsl:param name="value"/>
<xsl:param name="size"/>
<xsl:variable name="padding_char" select="' '" />
<xsl:variable name="a" select="for $n in 1 to $size - string-length(string($value)) return ' '"/>
<xsl:value-of select="concat($value, fn:string-join($a, ''))"/>
</xsl:function>

</xsl:stylesheet>

Hope this helps
Ivan Pedruzzi
Stylus Studio Team

Posttop
Sameer ShadabSubject: XSLT Requirement - something like duplicate elements
Author: Sameer Shadab
Date: 01 Jul 2005 05:23 AM
Hi Ivan Pedruzzi

Fantastic solutions, works like a dream. Thanks a lot buddy. Stylus Studio team rocks :)

cheers
Sameer

 
Topic Page 1 2 3 4 5 6 7 8 9 Go to previous topicPrev TopicGo to next topicNext Topic
Download A Free Trial of Stylus Studio 6 XML Professional Edition Today! Powered by Stylus Studio, the world's leading XML IDE for XML, XSLT, XQuery, XML Schema, DTD, XPath, WSDL, XHTML, SQL/XML, and XML Mapping!  
go

Log In Options

Site Map | Privacy Policy | Terms of Use | Trademarks
Stylus Scoop XML Newsletter:
W3C Member
Stylus Studio® and DataDirect XQuery ™are from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2016 All Rights Reserved.