unable to get sum using distinct loop sum xslt - xslt-3.0

I am new to xslt. I am creating a transform and need to calculate tax amount based on tax rate. The input file contains different tax rates and tax amount. The requirement is to look for common tax rates, take individual tax amount and sum them all. This creates a single T element.
If there are multiple tax rates, group common tax amounts and total them and form T element.
For example: Input file is:
<DATA>
<LIST_G_TRX>
<G_TRX>
<LIST_G_HEADER>
<G_HEADER>
<COUNTRYCODE>500</COUNTRYCODE>
<INVOICENUMBER>55005</INVOICENUMBER>
<CUSTOMER_TRX_ID>182066</CUSTOMER_TRX_ID>
<CUSTOMERID>5002013</CUSTOMERID>
<CUSTOMERORDERNUMBER>001</CUSTOMERORDERNUMBER>
<ORDERDATE>2019-01-09T00:00:00.000+00:00</ORDERDATE>
<INVOICEDATE>2019-01-09</INVOICEDATE>
<BILLTOCONTACT>XXXLutz Logistik AG</BILLTOCONTACT>
<BILLTONAME>XXXLutz Logistik AG</BILLTONAME>
<BILLTOADDRESS1>Römerstraße 999</BILLTOADDRESS1>
<BILLTOADDRESS2/>
<BILLTOADDRESS3/>
<BILLTOCITY>Wels</BILLTOCITY>
<BILLTOPOSTALCODE>4600</BILLTOPOSTALCODE>
<BILLTOCOUNTRYCODE>AT</BILLTOCOUNTRYCODE>
<CONTACTPHONENUMBER>11111111</CONTACTPHONENUMBER>
<CONTACTPHONEEXT/>
<CURRENCY>EUR</CURRENCY>
<CUSTOMERTAXID>ATU64784111</CUSTOMERTAXID>
<ODTAXID>FN 150931</ODTAXID>
<INVOICETYPE>R</INVOICETYPE>
<TOTALINVOICEVALUE>124.8</TOTALINVOICEVALUE>
<TOTALTAXABLEAMOUNT>104</TOTALTAXABLEAMOUNT>
<TOTALTAX>20.80</TOTALTAX>
<TOTALMISCCHARGE>0.00</TOTALMISCCHARGE>
<TOTALDETAILPRICE/>
<PAYERCUSTOMERID>5002013</PAYERCUSTOMERID>
<PAYERCONTACT>XXXLutz Logistik AG</PAYERCONTACT>
<PAYERNAME>XXXLutz Logistik AG</PAYERNAME>
<PAYERADDRESS1>Filialnummer ZL</PAYERADDRESS1>
<PAYERADDRESS2>Gewerbestrasse 29</PAYERADDRESS2>
<PAYERADDRESS3/>
<PAYERCITY>Sattledt</PAYERCITY>
<PAYERPOSTALCODE>4642</PAYERPOSTALCODE>
<PAYERCOUNTRY>AT</PAYERCOUNTRY>
<PAYERPHONENUMBER>22222222</PAYERPHONENUMBER>
<PAYERPHONEEXT/>
<SOLDTOCUSTOMERID>5002013</SOLDTOCUSTOMERID>
<SOLDTONAME>XXXLutz Logistik AG</SOLDTONAME>
<SOLDTOADDRESS1>Filialnummer ZL</SOLDTOADDRESS1>
<SOLDTOADDRESS2>Gewerbestrasse 29</SOLDTOADDRESS2>
<SOLDTOADDRESS3/>
<SOLDTOCITY>Sattledt</SOLDTOCITY>
<SOLDTOPOSTALCODE>4642</SOLDTOPOSTALCODE>
<SOLDTOCOUNTRY>AT</SOLDTOCOUNTRY>
<SOLDTOPHONENUMBER>22222222</SOLDTOPHONENUMBER>
<SOLDTOPHONEEXT/>
<SUPPLIERNAME>Viking Direkt GesmbH</SUPPLIERNAME>
<SUPPLIERADDRESS1>Tragweiner Str. 57</SUPPLIERADDRESS1>
<SUPPLIERADDRESS2/>
<SUPPLIERADDRESS3/>
<SUPPLIERCITY>Pregarten</SUPPLIERCITY>
<SUPPLIERPOSTALCODE>4230</SUPPLIERPOSTALCODE>
<SUPPLIERCOUNTRY>AT</SUPPLIERCOUNTRY>
<SUPPLIERPHONENUMBER/>
<SUPPLIERPHONEEXT/>
<REFERENCEINVOICENUMBER/>
<CREDITCARDNUMBER/>
<EMAILADDRESS/>
<DUEDATE>2019-01-14T00:00:00.000+00:00</DUEDATE>
<CREDITNOTEREASON/>
<LAST_PRINTED_DATE>2019-01-10T12:47:28.000+00:00</LAST_PRINTED_DATE>
<FIRST_PRINT_DATE>2019-01-10T12:47:28.000+00:00</FIRST_PRINT_DATE>
<PRINTING_COUNT>1</PRINTING_COUNT>
<TRANSACTION_SOURCE>Distributed Order Orchestration</TRANSACTION_SOURCE>
<LIST_G_LINES>
<G_LINES>
<CUSTOMER_TRX_ID>182066</CUSTOMER_TRX_ID>
<COUNTRYCODE>500</COUNTRYCODE>
<CUSTOMERID>5002013</CUSTOMERID>
<CUSTOMERORDERNUMBER>001</CUSTOMERORDERNUMBER>
<DELIVERYNOTENUMBER/>
<DELIVERYNOTELINENUMBER/>
<DELIVERYDATE>2019-01-09T00:00:00.000+00:00</DELIVERYDATE>
<INVOICELINENUMBER>2</INVOICELINENUMBER>
<ITEMNUMBER>6873291</ITEMNUMBER>
<INVOICEDQUANTITY>1</INVOICEDQUANTITY>
<PRICE>-20</PRICE>
<LINEAMOUNT>-20.00</LINEAMOUNT>
<ORDERNUMBER>840</ORDERNUMBER>
<UNITOFMEASURE>EA</UNITOFMEASURE>
<INVOICENUMBER>55005</INVOICENUMBER>
<TAXRATE/>
<TAXAMOUNT/>
<TAXCODE/>
<ITEMDESCRIPTION/>
<SHIPTOCONTACT/>
<SHIPTONAME>XXXLutz Logistik AG</SHIPTONAME>
<SHIPTOADDRESS1>Filialnummer ZL</SHIPTOADDRESS1>
<SHIPTOADDRESS2>Gewerbestrasse 29</SHIPTOADDRESS2>
<SHIPTOADDRESS3/>
<SHIPTOCITY>Sattledt</SHIPTOCITY>
<SHIPTOPOSTALCODE>4642</SHIPTOPOSTALCODE>
<SHIPTOCOUNTRY>AT</SHIPTOCOUNTRY>
<CONTACTPHONENUMBER>22222222</CONTACTPHONENUMBER>
<CONTACTPHONEEXT/>
<ORDERTYPE>R</ORDERTYPE>
<ORDERLINENUMBER>1</ORDERLINENUMBER>
<ORDERDATE>2019-01-09</ORDERDATE>
<CUSTOMERITEMDESCRIPTION/>
<INVOICELINECOMMENT1/>
<INVOICELINECOMMENT2/>
<TRANSACTIONID/>
<CUSTOMERCOSTCENTER/>
<CUSTOMERITEMNUMBER/>
<CUSTOMERORDERLINENUMBER/>
<ORDEREDQTY>1</ORDEREDQTY>
<SHIPPEDQTY>1</SHIPPEDQTY>
</G_LINES>
<G_LINES>
<CUSTOMER_TRX_ID>182066</CUSTOMER_TRX_ID>
<COUNTRYCODE>500</COUNTRYCODE>
<CUSTOMERID>5002013</CUSTOMERID>
<CUSTOMERORDERNUMBER>001</CUSTOMERORDERNUMBER>
<DELIVERYNOTENUMBER/>
<DELIVERYNOTELINENUMBER/>
<DELIVERYDATE/>
<INVOICELINENUMBER/>
<ITEMNUMBER/>
<INVOICEDQUANTITY/>
<PRICE/>
<LINEAMOUNT/>
<ORDERNUMBER/>
<UNITOFMEASURE/>
<INVOICENUMBER>55005</INVOICENUMBER>
<TAXRATE>20</TAXRATE>
<TAXAMOUNT>24.80</TAXAMOUNT>
<TAXCODE/>
<ITEMDESCRIPTION>HP 7612 e-All-in-One-GroAformatdrucker</ITEMDESCRIPTION>
<SHIPTOCONTACT/>
<SHIPTONAME/>
<SHIPTOADDRESS1/>
<SHIPTOADDRESS2/>
<SHIPTOADDRESS3/>
<SHIPTOCITY/>
<SHIPTOPOSTALCODE/>
<SHIPTOCOUNTRY/>
<CONTACTPHONENUMBER/>
<CONTACTPHONEEXT/>
<ORDERTYPE>R</ORDERTYPE>
<ORDERLINENUMBER/>
<ORDERDATE/>
<CUSTOMERITEMDESCRIPTION/>
<INVOICELINECOMMENT1/>
<INVOICELINECOMMENT2/>
<TRANSACTIONID/>
<CUSTOMERCOSTCENTER/>
<CUSTOMERITEMNUMBER/>
<CUSTOMERORDERLINENUMBER/>
<ORDEREDQTY/>
<SHIPPEDQTY/>
</G_LINES>
<G_LINES>
<CUSTOMER_TRX_ID>182066</CUSTOMER_TRX_ID>
<COUNTRYCODE>500</COUNTRYCODE>
<CUSTOMERID>5002013</CUSTOMERID>
<CUSTOMERORDERNUMBER>001</CUSTOMERORDERNUMBER>
<DELIVERYNOTENUMBER/>
<DELIVERYNOTELINENUMBER/>
<DELIVERYDATE/>
<INVOICELINENUMBER/>
<ITEMNUMBER/>
<INVOICEDQUANTITY/>
<PRICE/>
<LINEAMOUNT/>
<ORDERNUMBER/>
<UNITOFMEASURE/>
<INVOICENUMBER>55005</INVOICENUMBER>
<TAXRATE>20</TAXRATE>
<TAXAMOUNT>-4.00</TAXAMOUNT>
<TAXCODE/>
<ITEMDESCRIPTION>HP</ITEMDESCRIPTION>
<SHIPTOCONTACT/>
<SHIPTONAME/>
<SHIPTOADDRESS1/>
<SHIPTOADDRESS2/>
<SHIPTOADDRESS3/>
<SHIPTOCITY/>
<SHIPTOPOSTALCODE/>
<SHIPTOCOUNTRY/>
<CONTACTPHONENUMBER/>
<CONTACTPHONEEXT/>
<ORDERTYPE>R</ORDERTYPE>
<ORDERLINENUMBER/>
<ORDERDATE/>
<CUSTOMERITEMDESCRIPTION/>
<INVOICELINECOMMENT1/>
<INVOICELINECOMMENT2/>
<TRANSACTIONID/>
<CUSTOMERCOSTCENTER/>
<CUSTOMERITEMNUMBER/>
<CUSTOMERORDERLINENUMBER/>
<ORDEREDQTY/>
<SHIPPEDQTY/>
</G_LINES>
<G_LINES>
<CUSTOMER_TRX_ID>182066</CUSTOMER_TRX_ID>
<COUNTRYCODE>500</COUNTRYCODE>
<CUSTOMERID>5002013</CUSTOMERID>
<CUSTOMERORDERNUMBER>001</CUSTOMERORDERNUMBER>
<DELIVERYNOTENUMBER/>
<DELIVERYNOTELINENUMBER/>
<DELIVERYDATE>2019-01-09T00:00:00.000+00:00</DELIVERYDATE>
<INVOICELINENUMBER>1</INVOICELINENUMBER>
<ITEMNUMBER>6873291</ITEMNUMBER>
<INVOICEDQUANTITY>1</INVOICEDQUANTITY>
<PRICE>124</PRICE>
<LINEAMOUNT>124.00</LINEAMOUNT>
<ORDERNUMBER>840</ORDERNUMBER>
<UNITOFMEASURE>EA</UNITOFMEASURE>
<INVOICENUMBER>55005</INVOICENUMBER>
<TAXRATE/>
<TAXAMOUNT/>
<TAXCODE/>
<ITEMDESCRIPTION/>
<SHIPTOCONTACT/>
<SHIPTONAME>XXXLutz Logistik AG</SHIPTONAME>
<SHIPTOADDRESS1>Filialnummer ZL</SHIPTOADDRESS1>
<SHIPTOADDRESS2>Gewerbestrasse 29</SHIPTOADDRESS2>
<SHIPTOADDRESS3/>
<SHIPTOCITY>Sattledt</SHIPTOCITY>
<SHIPTOPOSTALCODE>4642</SHIPTOPOSTALCODE>
<SHIPTOCOUNTRY>AT</SHIPTOCOUNTRY>
<CONTACTPHONENUMBER>22222222</CONTACTPHONENUMBER>
<CONTACTPHONEEXT/>
<ORDERTYPE>R</ORDERTYPE>
<ORDERLINENUMBER>1</ORDERLINENUMBER>
<ORDERDATE>2019-01-09</ORDERDATE>
<CUSTOMERITEMDESCRIPTION/>
<INVOICELINECOMMENT1/>
<INVOICELINECOMMENT2/>
<TRANSACTIONID/>
<CUSTOMERCOSTCENTER/>
<CUSTOMERITEMNUMBER/>
<CUSTOMERORDERLINENUMBER/>
<ORDEREDQTY>1</ORDEREDQTY>
<SHIPPEDQTY>1</SHIPPEDQTY>
</G_LINES>
</LIST_G_LINES>
My output should be similar to this:
<H>
<tax rate 20>
<tax amount 102.60>
</H>
<H>
<tax rate 7>
<tax amount 21.50>
</H>
<H>
<tax rate 19>
<tax amount 13.28>
</H>
My xslt is:
<xsl:variable name="vTaxRateCount" select="count(distinct-values(LIST_G_LINES/G_LINES/TAXRATE))"/>
<xsl:variable name="vDistinct">
<xsl:for-each select="fn:distinct-values(LIST_G_LINES/G_LINES/TAXRATE)">
<xsl:element name="Values">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="vPath" select="LIST_G_LINES/G_LINES/TAXAMOUNT"/>
<xsl:for-each select="$vDistinct/Values">
<xsl:variable name="vUniqueVal" select="."/>
<xsl:for-each select="LIST_G_LINES/G_LINES/TAXRATE=.">
<xsl:element name="TaxAmount">
<xsl:value-of select="sum($vPath[#TAXRATE = $vUniqueVal])"/>
<xsl:value-of select="$vUniqueVal"/>
</xsl:element>
</xsl:for-each>
</xsl:for-each>
This code doesn't seem to work. Could you please help.

From your input and given XSLT, assuming the input file as below: (if it is XML)
<?xml version="1.0" encoding="UTF-8"?>
<LIST_G_LINES>
<G_LINES>
<Taxrates> 20 <Taxamount> 1.60 </Taxamount></Taxrates>
</G_LINES>
<G_LINES>
<Taxrates> 7 <Taxamount> 21.50 </Taxamount></Taxrates>
</G_LINES>
<G_LINES>
<Taxrates> 19 <Taxamount> 1.60 </Taxamount></Taxrates>
</G_LINES>
<G_LINES>
<Taxrates> 19 <Taxamount> 11.68 </Taxamount></Taxrates>
</G_LINES>
<G_LINES>
<Taxrates> 20 <Taxamount> 101 </Taxamount></Taxrates>
</G_LINES>
</LIST_G_LINES>
An XSLT 2.0 solution can be as following:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/LIST_G_LINES">
<xsl:for-each-group select="G_LINES" group-by="Taxrates/text()">
<H>
<TaxRate>
<xsl:value-of select="current-grouping-key()" />
</TaxRate>
<TaxAmount>
<xsl:value-of select="sum(current-group()/Taxrates/Taxamount)" />
</TaxAmount>
</H>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
Refer here to see the output
Edit: Based on your updated XML, you can try the following XSLT 3.0 solution:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math" version="3.0">
<xsl:mode streamable="yes" />
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<xsl:for-each-group select="DATA/LIST_G_TRX/G_TRX/LIST_G_HEADER/G_HEADER/LIST_G_LINES/G_LINES" composite="yes" group-by="TAXRATE">
<xsl:if test="current-grouping-key() != ''">
<H>
<TaxRate>
<xsl:value-of select="current-grouping-key()" />
</TaxRate>
<TaxAmount>
<xsl:value-of select="sum(current-group()/TAXAMOUNT)" />
</TaxAmount>
</H>
</xsl:if>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>

Related

Find and ReplaceAll : To get Find Value in Attribute and Replace with Content using XSLT3.0

I would like to do Find and Replace using XSLT 3.0. When I have found the value from TextStyle element with attribute of FONTSTYLE value it should store in variables and replace with the text.
Found Pattern is : <String ID="p1_w5" CONTENT="Human" HPOS="261.948" VPOS="75.8759" STYLEREFS="font1"/>
Replace Pattern Expect this : <String ID="p1_w5" CONTENT="<bold>Human</bold>" HPOS="261.948" VPOS="75.8759" STYLEREFS="font1"/>
How do achieve my requirements using XSLT Find and Replace?
My Current Input XML File is :
<?xml version="1.0" encoding="UTF-8"?>
<ALTO>
<STYLES>
<TextStyle ID="font1" FONTFAMILY="cambria" FONTSIZE="12.000" FONTSTYLE="bold"/>
<TextStyle ID="font2" FONTFAMILY="cambria" FONTSIZE="7.920" FONTSTYLE="sup"/>
<TextStyle ID="font3" FONTFAMILY="cambria" FONTSIZE="12.000" FONTSTYLE="it"/>
</STYLES>
<LAYOUT>
<TextBlock ID="p1_b1" HPOS="83.6703" VPOS="75.8759" HEIGHT="10.6680" WIDTH="445.700">
<TextLine WIDTH="445.700" HEIGHT="10.6680" ID="p1_t1" HPOS="83.6703" VPOS="75.8759">
<String ID="p1_w1" CONTENT="Hie" HPOS="83.6703" VPOS="75.8759" STYLEREFS="font0"/>
<String ID="p1_w2" CONTENT="org" HPOS="154.915" VPOS="75.8759" STYLEREFS="font0"/>
<String ID="p1_w3" CONTENT="of" HPOS="228.005" VPOS="75.8759" STYLEREFS="font0"/>
<String ID="p1_w4" CONTENT="the" HPOS="241.393" VPOS="75.8759" STYLEREFS="font0"/>
<String ID="p1_w5" CONTENT="Human" HPOS="261.948" VPOS="75.8759" STYLEREFS="font1"/>
<String ID="p1_w6" CONTENT="cell" HPOS="303.263" VPOS="75.8759" STYLEREFS="font0"/>
<String ID="p1_w8" CONTENT="a" HPOS="354.900" VPOS="75.8759" STYLEREFS="font0"/>
<String ID="p1_w9" CONTENT="CANCER" HPOS="363.965" VPOS="75.8759" STYLEREFS="font3"/>
</TextLine>
</TextBlock>
</LAYOUT>
</ALTO>
Tried XSLT file :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fnc="http://www.xsweet.org/2022/ext"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output method="xml" indent="yes"/>
<xsl:preserve-space elements="*"/>
<xsl:template match="/|node()|*|#*">
<xsl:copy>
<xsl:apply-templates select="node() | * | #*"/>
</xsl:copy>
</xsl:template>
<xsl:param name="styletag1" select="TextStyle[#FONTSTYLE = 'sup']"/>
<xsl:param name="styletag2" select="TextStyle[#FONTSTYLE = 'it']"/>
<xsl:param name="styletag3" select="TextStyle[#FONTSTYLE = 'bold']"/>
<xsl:template match="/|node()|*|#*">
<xsl:copy>
<xsl:apply-templates select="node() | * | #*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="LAYOUT/TextBlock/TextLine/String[$styletag1]">
<xsl:message>Superscript Need to Replace All</xsl:message>
</xsl:template>
</xsl:stylesheet>
You can do
<xsl:key name="text-style" match="TextStyle/#FONTSTYLE" use="../#ID"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="String[key('text-style', #STYLEREFS)]/#CONTENT">
<xsl:attribute name="{name()}" select="'<' || key('text-style', ../#STYLEREFS) || '>' || . || '</' || key('text-style', ../#STYLEREFS) || '>'"/>
</xsl:template>
but of course the output is XML with entity references in the attribute value e.g.
<String ID="p1_w5" CONTENT="<bold>Human</bold>" HPOS="261.948" VPOS="75.8759" STYLEREFS="font1"/>
If you really want e.g. CONTENT="<bold>Human</bold>" then use a character map
<xsl:output use-character-maps="m1"/>
<xsl:character-map name="m1">
<xsl:output-character character="<" string="<"/>
<xsl:output-character character=">" string=">"/>
</xsl:character-map>

XSLT Can't Read an Excel XML File?

I'm using XSLT / XPath to browse some of the XML files you get when you unzip an Excel file. I found a "relationships" file workbook.xml.rels that I don't seem to be able to read, using code similar to that which successfully read the workbook.xml file.
Here's some of the workbook.xml file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
...
<sheets>
<sheet name="Sheet1"
sheetId="2"
r:id="rId1"/>
<sheet name="Test Sheet"
sheetId="1"
r:id="rId2"/>
</sheets>
...
</workbook>
Here's the workbook.xml.rels file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId3"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"
Target="theme/theme1.xml"/>
<Relationship Id="rId2"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
Target="worksheets/sheet2.xml"/>
<Relationship Id="rId1"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
Target="worksheets/sheet1.xml"/>
<Relationship Id="rId5"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"
Target="sharedStrings.xml"/>
<Relationship Id="rId4"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"
Target="styles.xml"/>
</Relationships>
Here's some of the XSLT:
<?xml version="1.0"?>
<!-- greeting.xsl -->
<xsl:stylesheet
...
<xsl:output method="text"/>
<xsl:variable name="baseDir" select="replace(document-uri(.), '(.*[\\/]xl).*', '$1/')"/>
<xsl:variable name="workbook" select="concat($baseDir, 'workbook.xml')"/>
<xsl:variable name="theSheetId" select="doc($workbook)/workbook/sheets/sheet[matches(#name, 'Test Sheet')]/#r:id"/>
<xsl:variable name="workbook_rels" select="concat($baseDir, '_rels/workbook.xml.rels')"/>
<!-- code to read workbook.xml.rels -->
<xsl:variable name="theSheet" select="doc($workbook_rels)/Relationships/Relationship[matches(#Id, $theSheetId)]/#Target"/>
<xsl:template match="/">
<xsl:text>
baseDir = </xsl:text><xsl:value-of select="$baseDir"/>
<xsl:text>
workbook = </xsl:text><xsl:value-of select="$workbook"/>
<xsl:text>
workbook_rels = </xsl:text><xsl:value-of select="$workbook_rels"/>
<xsl:text>
theSheetId = </xsl:text><xsl:value-of select="$theSheetId"/>
<xsl:text>
theSheet = </xsl:text><xsl:value-of select="$theSheet"/>
<xsl:text>
end</xsl:text>
</xsl:template>
</xsl:stylesheet>
And the output:
baseDir = file:/C:/Training/sandbox/conv_/xl/
workbook = file:/C:/Training/sandbox/conv_/xl/workbook.xml
workbook_rels = file:/C:/Training/sandbox/conv_/xl/_rels/workbook.xml.rels
theSheetId = rId2
theSheet = **<I get nothing here>**
end
You can see that 'theSheetID' variable is correctly set when reading workbook.xml. But when I use that variable to get the corresponding Target value into 'theSheet' variable from workbook.xml.rels, I get nothing. I tried replacing the matches expression with just a number but I still get nothing. Is there a problem from reading this type of file?
Suggestions? Thanks!
The use of matches and replace suggests you are using an XSLT 2 or 3 processor and that way XSLT 2 or 3 where you can certainly declare xpath-default-namespace, you just have to understand you have to change that in the sections that deal with elements from a different namespace e.g. <xsl:variable name="theSheet" select="doc($workbook_rels)/Relationships/Relationship[matches(#Id, $theSheetId)]/#Target" xpath-default-namespace="http://schemas.openxmlformats.org/package/2006/relationships"/>.
Given the samples I would rather use a key <xsl:key name="rel" match="Relationships/Relationship" use="#Id" xpath-default-namespace="http://schemas.openxmlformats.org/package/2006/relationships"/> and then use <xsl:variable name="theSheet" select="key('rel,$theSheetId, doc($workbook_rels))/#Target"/> but the use of xpath-default-namespace to declare the relevant namespace when selecting elements from a particular document is probably what is missing in your XSLT.

How to process two parts of a single xml by streaming?

I have a really large XML that has two different sets of data. I need to stream through one and do a lookup on the other. My Data looks like below
<?xml version="1.0" encoding="utf-8"?>
<Root>
<EmployeePersonal>
<Employee>
<ID>21234</ID>
<Name>Jim Carrey</Name>
<Age>43</Age>
<City>Chicago</City>
<State>IL</State>
</Employee>
<Employee>
<ID>41876</ID>
<Name>Edward Norton</Name>
<Age>33</Age>
<City>New York</City>
<State>NY</State>
</Employee>
<Employee>
<ID>51239</ID>
<Name>Eli Roth</Name>
<Age>46</Age>
<City>Los Angeles</City>
<State>CA</State>
</Employee>
</EmployeePersonal>
<EmployeeEmployment>
<Empl>
<Emplid>21234</Emplid>
<Title>HR Partner</Title>
<HireDate>2008-12-29</HireDate>
</Empl>
<Empl>
<Emplid>41876</Emplid>
<Title>Comp Partner</Title>
<HireDate>1999-07-09</HireDate>
</Empl>
<Empl>
<Emplid>51239</Emplid>
<Title>Programmer</Title>
<HireDate>2004-12-06</HireDate>
</Empl>
</EmployeeEmployment>
</Root>
I would like to loop through the /Root/EmployeePersonal data and lookup the /Root/EmployeeEmployment by matching on the employee id.
I tried to loop through one and then load into a map and then loop through the other, but kept getting an error. Finally I tried loading one set into a variable and then tried to stream the other, but in vain. This is what I've tried so far.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="3.0">
<xsl:mode streamable="yes" on-no-match="shallow-skip"/>
<xsl:output indent="no"/>
<xsl:variable name="vEmploymentData" select="Root/copy-of(EmployeeEmployment)"/>
<xsl:template match="/Root/EmployeePersonal">
<AllEmployeeData>
<xsl:for-each select="Employee/copy-of()">
<Employee>
<xsl:copy-of select="./*"/>
<xsl:copy-of select="$vEmploymentData/Empl[Emplid=current()/ID]/*[local-name() ne 'Emplid']"/>
</Employee>
</xsl:for-each>
</AllEmployeeData>
</xsl:template>
</xsl:stylesheet>
I need to merge these two sets of data together. Since the data is huge, is there a way to stream both sets of data in?
Thanks
Given that you need to different sets of the data at the same time to compare and merge them I am not sure there is an easy single pass, streamable and therefore forwards-only approach, so some easy way around that would be to set up the same document twice as an xsl:merge-source for an xsl:merge:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all">
<xsl:param name="input-uri" as="xs:string" select="'input1.xml'"/>
<xsl:output indent="yes"/>
<xsl:template name="xsl:initial-template">
<AllEmployeeData>
<xsl:merge>
<xsl:merge-source name="emp-details1" for-each-source="$input-uri" streamable="yes" select="Root/EmployeePersonal/Employee">
<xsl:merge-key select="ID"/>
</xsl:merge-source>
<xsl:merge-source name="emp-details2" for-each-source="$input-uri" streamable="yes" select="Root/EmployeeEmployment/Empl">
<xsl:merge-key select="Emplid"/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:copy>
<xsl:copy-of select="current-merge-group('emp-details1')/*, current-merge-group('emp-details2')/(* except Emplid)"/>
</xsl:copy>
</xsl:merge-action>
</xsl:merge>
</AllEmployeeData>
</xsl:template>
</xsl:stylesheet>
As xsl:merge works with a snapshot, that has the advantage that the access to ID and Emplid child is not a problem. You also don't have to take any particular action to buffer data in maps or accumulators. The main disadvantage is that xsl:merge expects the sources to be ordered by the merge keys, that seems to be the case for your sample data but I am not sure that will be true for your complete data.
You would run such a stylesheet with Saxon 9 EE using the command line option -it to start without a primary input but with the initial template named xsl:initial-template instead.
As an alternative approach that only reads through the main input once but buffers the EmployeePersonal/Employee in an accumulator using a Saxon 9.9 EE specific saxon:capture attribute you could use:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:saxon="http://saxon.sf.net/"
exclude-result-prefixes="#all">
<xsl:output indent="yes"/>
<xsl:mode streamable="yes" on-no-match="shallow-skip" use-accumulators="emp-details1"/>
<xsl:accumulator name="emp-details1" streamable="yes" as="element(Employee)*" initial-value="()">
<xsl:accumulator-rule match="EmployeePersonal/Employee" phase="end" saxon:capture="yes" select="$value, ."/>
</xsl:accumulator>
<xsl:template match="/*">
<AllEmployeeData>
<xsl:apply-templates/>
</AllEmployeeData>
</xsl:template>
<xsl:template match="EmployeeEmployment/Empl">
<Employee>
<xsl:variable name="this" select="copy-of()"/>
<xsl:copy-of select="accumulator-before('emp-details1')[ID = $this/Emplid]/*, $this/(* except Emplid)"/>
</Employee>
</xsl:template>
</xsl:stylesheet>
This reads through the input only once but buffers all EmployeePersonal/Employee in memory and then uses the buffered/accumulated elements later one when EmployeeEmployment/Empl is matched to output the necessary corresponding data. This also of course, as the output is created when matching EmployeeEmployment/Empl, requires the presence of all ids in that data, I am not sure that is the case or whether the EmployeePersonal/Employee is the main input and you only look for matching EmployeeEmployment/Empl if it exists.
Finally, you could as well try to store the details of EmployeePersonal/Employee in an accumulator using a map and then access this from the template for EmployeeEmployment/Empl:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:saxon="http://saxon.sf.net/"
expand-text="yes"
exclude-result-prefixes="#all">
<xsl:output indent="yes"/>
<xsl:mode streamable="yes" on-no-match="shallow-skip" use-accumulators="#all"/>
<xsl:accumulator name="current-emp-id" streamable="yes" as="xs:integer?" initial-value="()">
<xsl:accumulator-rule match="EmployeePersonal/Employee/ID/text()" select="xs:integer(.)"/>
</xsl:accumulator>
<xsl:accumulator name="emp-details" streamable="yes" as="map(xs:integer, map(xs:string, xs:string))" initial-value="map{}">
<xsl:accumulator-rule match="EmployeePersonal/Employee/ID/text()" select="map:put($value, xs:integer(.), map{})"/>
<xsl:accumulator-rule match="EmployeePersonal/Employee/*[not(self::ID)]/text()"
select="map:put($value, accumulator-before('current-emp-id'), map:put(map:get($value, accumulator-before('current-emp-id')), local-name(..), string()))"/>
</xsl:accumulator>
<xsl:template match="/*">
<AllEmployeeData>
<xsl:apply-templates/>
</AllEmployeeData>
</xsl:template>
<xsl:template match="EmployeeEmployment/Empl">
<Employee>
<xsl:variable name="this" select="copy-of()"/>
<ID>{$this/Emplid}</ID>
<xsl:apply-templates select="map:get(accumulator-before('emp-details'), xs:integer($this/Emplid))" mode="entry-to-element"/>
<xsl:copy-of select="$this/(* except Emplid)"/>
</Employee>
</xsl:template>
<xsl:template match=".[. instance of map(*)]" mode="entry-to-element">
<xsl:variable name="map" select="."/>
<xsl:for-each select="map:keys(.)">
<xsl:element name="{.}">{map:get($map, .)}</xsl:element>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Of course it will still buffer all the EmployeePersonal/Employee data, only this time using a light-weight map instead of a sequence of XML snapshot elements. The main disadvantage is that XSLT 3/XPath 3.1 maps have no order so unless you later spell out each entry you are looking for in the wanted order you get the results in a random order. In the example above I have simply used a for-each to convert map entries back to XML elements so the order is a random order and not the one of the input XML (that the xsl:merge approach or the saxon:capture approach would preserve).
As you asked in a comment about using xsl:merge but provide the input as a primary input source, the only way I can think of is to use it as a dummy streamable input and then to provide its document-uri() for the xsl:merge/xsl:merge-source, that is, to adapt the code from above to
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all">
<xsl:mode streamable="yes"/>
<xsl:output indent="yes"/>
<xsl:template match="/">
<AllEmployeeData>
<xsl:variable name="input-uri" as="xs:anyURI" select="document-uri()"/>
<xsl:message select="$input-uri"/>
<xsl:merge>
<xsl:merge-source name="emp-details1" for-each-source="$input-uri" streamable="yes" select="Root/EmployeePersonal/Employee">
<xsl:merge-key select="ID"/>
</xsl:merge-source>
<xsl:merge-source name="emp-details2" for-each-source="$input-uri" streamable="yes" select="Root/EmployeeEmployment/Empl">
<xsl:merge-key select="Emplid"/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:copy>
<xsl:copy-of select="current-merge-group('emp-details1')/*, current-merge-group('emp-details2')/(* except Emplid)"/>
</xsl:copy>
</xsl:merge-action>
</xsl:merge>
</AllEmployeeData>
</xsl:template>
</xsl:stylesheet>
Interestingly enough, that works with Saxon 9.7 EE (of course that opening the same input three times for streaming) but fails with an error " XTSE3430: Template rule is not streamable * The merge-source/#select expression is not striding" in Saxon 9.8 and 9.9 EE.
Not sure whether that helps, in earlier questions you seemed to indicate that the tool you use embeds Saxon 9.7 EE so it might be an option.

Populating nodes based on condition in Receiver file

I need to populate one segment based on input values.the requirement like below
in the input payload we are getting below segment like
<charac>
<charactername>
<charactervalue>
</charac>
so the above segment may come multiple times but based on the few values only need to populate the segment for example,
<charac>
<charactername>print</charactername>
<charactervalue>123</charactervalue>
</charac>
<charac>
<charactername>comp</charactername>
<charactervalue>1234</charactervalue>
</charac>
<charac>
<charactername>pal</charactername>
<charactervalue>1235</charactervalue>
</charac>
so here only I need populate segment when charactername is equal to only print or comp
the receiver structure the segment is
<e1edl1>
<at>
<rt>
</e1edl1>
so the output should be like
<e1edl1>
<at>print</at>
<rt>123</rt>
</e1edl1>
<e1edl1>
<at>comp</at>
<rt>1234</rt>
</e1edl1>
I tried with below code
<ns0:if test="count(./charac)!=0">
<ns0:for-each select="./charac">
<e1edl1 SEGMENT="1">
<at>
<ns0:value-of select="charactername" />
</at>
<rt>
<ns0:value-of select="charactervalue" />
</rt>
</e1edl1>
</ns0:for-each>
</ns0:if>
could you please help on this.
Regards,
Janardhan
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="//charac[charactername='print' or charactername='comp']" />
</xsl:template>
<xsl:template match="charac">
<e1edl1>
<at><xsl:value-of select="charactername" /></at>
<rt><xsl:value-of select="charactervalue" /></rt>
</e1edl1>
</xsl:template>
</xsl:stylesheet>

removing namespace in node level

below is my input xml code
<?xml version="1.0" encoding="UTF-8"?>
<EPCISDocument xmlns:ns1="http://apse.com" schemaVersion="" creationDate="">
<EPCISHeader>
<StandardBusinessDocumentHeader>
<HeaderVersion/>
<Sender>
<Identifier Authority=""/>
<ContactInformation>
<Contact/>
<EmailAddress/>
<FaxNumber/>
<TelephoneNumber/>
<ContactTypeIdentifier/>
</ContactInformation>
</Sender>
<Receiver>
<Identifier Authority=""/>
<ContactInformation>
<Contact/>
<EmailAddress/>
<FaxNumber/>
<TelephoneNumber/>
<ContactTypeIdentifier/>
</ContactInformation>
</Receiver>
<Manifest>
<NumberOfItems/>
<ManifestItem>
<MimeTypeQualifierCode/>
<UniformResourceIdentifier/>
<Description/>
<LanguageCode/>
</ManifestItem>
</Manifest>
<BusinessScope>
<Scope>
<BusinessService>
<BusinessServiceName/>
<ServiceTransaction TypeOfServiceTransaction="" IsNonRepudiationRequired="" IsAuthenticationRequired="" IsNonRepudiationOfReceiptRequired="" IsIntegrityCheckRequired="" IsApplicationErrorResponseRequired="" TimeToAcknowledgeReceipt="" TimeToAcknowledgeAcceptance="" TimeToPerform=""/>
</BusinessService>
<CorrelationInformation>
<RequestingDocumentCreationDateTime/>
<RequestingDocumentInstanceIdentifier/>
<ExpectedResponseDateTime/>
</CorrelationInformation>
</Scope>
</BusinessScope>
</StandardBusinessDocumentHeader>
</EPCISHeader>
<EPCISBody>
<EventList>
<ObjectEvent>
<eventTime/>
<recordTime/>
<eventTimeZoneOffset/>
<epcList>
<epc type=""/>
</epcList>
<action/>
<bizStep/>
<disposition/>
<readPoint>
<id/>
</readPoint>
<bizLocation>
<id/>
</bizLocation>
<bizTransactionList>
<bizTransaction type=""/>
</bizTransactionList>
<GskEpcExtension>
<manufacturingDate>1234</manufacturingDate>
</GskEpcExtension>
</ObjectEvent>
</EventList>
</EPCISBody>
</EPCISDocument>
I want to add some prefixes, so I have applied below xslt code which got from stackoverflow and it is working fine. but with below code I am getting namespaces in node level.below is the xsl code.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:gsk="http://apse.com">
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="GskEpcExtension|GskEpcExtension//*">
<xsl:element name="gsk:{name()}" namespace="http://epcis.gsk.com">
<xsl:copy-of select="namespace::*"/>
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
<xsl:template match="StandardBusinessDocumentHeader|StandardBusinessDocumentHeader//*">
<xsl:element name="sbdh:{name()}" namespace="http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader">
<xsl:copy-of select="namespace::*"/>
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
output for this xsl code is
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="Untitled3.xslt"?>
<EPCISDocument xmlns:ns1="http://apse.com" schemaVersion="" creationDate="">
<EPCISHeader>
<sbdh:StandardBusinessDocumentHeader xmlns:sbdh="http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader">
<sbdh:HeaderVersion/>
<sbdh:Sender>
<sbdh:Identifier Authority=""/>
<sbdh:ContactInformation>
<sbdh:Contact/>
<sbdh:EmailAddress/>
<sbdh:FaxNumber/>
<sbdh:TelephoneNumber/>
<sbdh:ContactTypeIdentifier/>
</sbdh:ContactInformation>
</sbdh:Sender>
<sbdh:Receiver>
<sbdh:Identifier Authority=""/>
<sbdh:ContactInformation>
<sbdh:Contact/>
<sbdh:EmailAddress/>
<sbdh:FaxNumber/>
<sbdh:TelephoneNumber/>
<sbdh:ContactTypeIdentifier/>
</sbdh:ContactInformation>
</sbdh:Receiver>
<sbdh:Manifest>
<sbdh:NumberOfItems/>
<sbdh:ManifestItem>
<sbdh:MimeTypeQualifierCode/>
<sbdh:UniformResourceIdentifier/>
<sbdh:Description/>
<sbdh:LanguageCode/>
</sbdh:ManifestItem>
</sbdh:Manifest>
<sbdh:BusinessScope>
<sbdh:Scope>
<sbdh:BusinessService>
<sbdh:BusinessServiceName/>
<sbdh:ServiceTransaction TypeOfServiceTransaction="" IsNonRepudiationRequired="" IsAuthenticationRequired="" IsNonRepudiationOfReceiptRequired="" IsIntegrityCheckRequired="" IsApplicationErrorResponseRequired="" TimeToAcknowledgeReceipt="" TimeToAcknowledgeAcceptance="" TimeToPerform=""/>
</sbdh:BusinessService>
<sbdh:CorrelationInformation>
<sbdh:RequestingDocumentCreationDateTime/>
<sbdh:RequestingDocumentInstanceIdentifier/>
<sbdh:ExpectedResponseDateTime/>
</sbdh:CorrelationInformation>
</sbdh:Scope>
</sbdh:BusinessScope>
</sbdh:StandardBusinessDocumentHeader>
</EPCISHeader>
<EPCISBody>
<EventList>
<ObjectEvent>
<eventTime/>
<recordTime/>
<eventTimeZoneOffset/>
<epcList>
<epc type=""/>
</epcList>
<action/>
<bizStep/>
<disposition/>
<readPoint>
<id/>
</readPoint>
<bizLocation>
<id/>
</bizLocation>
<bizTransactionList>
<bizTransaction type=""/>
</bizTransactionList>
<gsk:GskEpcExtension xmlns:gsk="http://epcis.gsk.com">
<gsk:manufacturingDate>1234</gsk:manufacturingDate>
</gsk:GskEpcExtension>
</ObjectEvent>
in the output payload for gskepcextension and standardbusinessdocuemnt header the namespaces are appearing but I need the output in below format for both nodes and the entire output structure is mentioned below. please check and help on this.
<?xml version="1.0" encoding="UTF-8"?>
<epcis:EPCISDocument xmlns:epcis="urn:epcglobal:epcis:xsd:1" xmlns:sbdh="http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader" xmlns:gsk="http://epcis.gsk.com" schemaVersion="1.0" creationDate="2013-05-16T13:23:36Z" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
<EPCISHeader>
<sbdh:StandardBusinessDocumentHeader>
<sbdh:HeaderVersion/>
<sbdh:Sender>
<sbdh:Identifier Authority="String">5051150024380</sbdh:Identifier>
<!-- This is optional information -->
<sbdh:ContactInformation>
<sbdh:Contact>String</sbdh:Contact>
<sbdh:EmailAddress>String</sbdh:EmailAddress>
<sbdh:FaxNumber>String</sbdh:FaxNumber>
<sbdh:TelephoneNumber>String</sbdh:TelephoneNumber>
<sbdh:ContactTypeIdentifier>String</sbdh:ContactTypeIdentifier>
</sbdh:ContactInformation>
</sbdh:Sender>
<sbdh:Receiver>
<sbdh:Identifier Authority="String">5051150018624</sbdh:Identifier>
<!-- This is optional information -->
<sbdh:ContactInformation>
<sbdh:Contact>String</sbdh:Contact>
<sbdh:EmailAddress>String</sbdh:EmailAddress>
<sbdh:FaxNumber>String</sbdh:FaxNumber>
<sbdh:TelephoneNumber>String</sbdh:TelephoneNumber>
<sbdh:ContactTypeIdentifier>String</sbdh:ContactTypeIdentifier>
</sbdh:ContactInformation>
</sbdh:Receiver>
<sbdh:DocumentIdentification>
<sbdh:Standard/>
<sbdh:TypeVersion/>
<sbdh:InstanceIdentifier>39cf981e070111e6838b0000362219a6</sbdh:InstanceIdentifier>
<sbdh:Type/>
<sbdh:CreationDateAndTime>2001-12-17T09:30:47Z</sbdh:CreationDateAndTime>
</sbdh:DocumentIdentification>
</sbdh:StandardBusinessDocumentHeader>
</EPCISHeader>
<EPCISBody>
<EventList>
<ObjectEvent>
<eventTime>2015-10-21T17:31:12.1530000+00:00</eventTime>
<eventTimeZoneOffset>+02:00</eventTimeZoneOffset>
<epcList>
<epc>urn:epc:id:sgtin:8806500.000122.2F52DTV751</epc>
<epc>urn:epc:id:sgtin:8806500.000122.23037KDFCV</epc>
<epc>urn:epc:id:sgtin:8806500.000122.2RPZF7GAAB</epc>
<epc>urn:epc:id:sgtin:8806500.000122.2HSWA43EV2</epc>
<epc>urn:epc:id:sgtin:8806500.000122.2S0Z8P3VHV</epc>
</epcList>
<action>ADD</action>
<bizStep>urn:epcglobal:cbv:bizstep:commissioning</bizStep>
<disposition>urn:epcglobal:cbv:disp:active</disposition>
<bizLocation>
<id>urn:epc:id:sgln:4028685.00000.0</id>
</bizLocation>
<gsk:GskEpcExtension>
<gsk:additionalTradeItemIdentificationValue>199610</gsk:additionalTradeItemIdentificationValue>
<gsk:lotNumber>15L011</gsk:lotNumber>
<gsk:itemExpirationDate>20171006</gsk:itemExpirationDate>
<gsk:manufacturingDate/>
<gsk:gtin>08806500001224</gsk:gtin>
<gsk:nhrn> </gsk:nhrn>
</gsk:GskEpcExtension>
</ObjectEvent>
</EventList>
</EPCISBody>
</epcis:EPCISDocument>
It seems you only need to add one more template:
<xsl:template match="EPCISDocument">
<epcis:EPCISDocument xmlns:epcis="urn:epcglobal:epcis:xsd:1">
<xsl:apply-templates select="node()|#*"/>
</epcis:EPCISDocument>
</xsl:template>
I would also suggest moving all your namespace declarations to the top level element, so that eventually your stylesheet looks something like:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:epcis="urn:epcglobal:epcis:xsd:1"
xmlns:sbdh="http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader"
xmlns:gsk="http://epcis.gsk.com">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="EPCISDocument">
<epcis:EPCISDocument>
<xsl:apply-templates select="node()|#*"/>
</epcis:EPCISDocument>
</xsl:template>
<xsl:template match="GskEpcExtension|GskEpcExtension//*">
<xsl:element name="gsk:{name()}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
<xsl:template match="StandardBusinessDocumentHeader|StandardBusinessDocumentHeader//*">
<xsl:element name="sbdh:{name()}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

Resources