How can I eliminate a duplicate result in XSLT 1.0? - xslt-1.0

I am using the Altova mapping tool and I cannot find an option on how to eliminate a duplicate value so I am trying to update the XSLT file directly and I cannot figure out how to do this. Below is the XSLT file, the problem is in the Detail06 section.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <xsl:template match="/">
<AsyncBarcode>
<xsl:variable name="var1_instance" select="." />
<xsl:for-each select="$var1_instance/n:SyncReceiveDelivery">
<xsl:variable name="var2_SyncReceiveDelivery" select="." />
<Prefix>
<xsl:for-each select="n:DataArea/n:Sync/n:AccountingEntityID">
<CompanyID>
<xsl:value-of select="string(.)" />
</CompanyID>
</xsl:for-each>
<xsl:for-each select="n:DataArea/n:Sync/n:AccountingEntityID">
<ExternalPartnerID>
<xsl:value-of select="string(.)" />
</ExternalPartnerID>
</xsl:for-each>
<DocumentType>
<xsl:value-of select="'AsyncBarcode'" />
</DocumentType>
<xsl:for-each select="n:ApplicationArea/n:BODID">
<DocumentNumber>
<xsl:value-of select="substring-after(substring-before(string(.), ':1?'), 'Infor:')" />
</DocumentNumber>
</xsl:for-each>
<TransactionDirection>
<xsl:value-of select="'I'" />
</TransactionDirection>
<DateStamp>
<xsl:value-of select="substring-before(string(n:ApplicationArea/n:CreationDateTime), 'T')" />
</DateStamp>
<TimeStamp>
<xsl:value-of select="substring-before(substring-after(string(n:ApplicationArea/n:CreationDateTime), 'T'), 'Z')" />
</TimeStamp>
<xsl:for-each select="n:ApplicationArea/n:BODID">
<ControlNumber>
<xsl:value-of select="substring-after(substring-before(string(.), ':1?'), 'Infor:')" />
</ControlNumber>
</xsl:for-each>
</Prefix>
<Header00>
<TransactionDefinitionKey>
<xsl:value-of select="'25'" />
</TransactionDefinitionKey>
<xsl:for-each select="n:DataArea/n:Sync/n:AccountingEntityID">
<CompanyID0>
<xsl:value-of select="string(.)" />
</CompanyID0>
</xsl:for-each>
<xsl:for-each select="n:DataArea/n:ReceiveDelivery/n:ReceiveDeliveryHeader/n:DocumentReference/n:DocumentID">
<xsl:variable name="var14_DocumentID" select="." />
<xsl:if test="$var14_DocumentID/n:ID/#location">
<BranchID>
<xsl:value-of select="substring-before(string(n:ID/#location), '-B')" />
</BranchID>
</xsl:if>
</xsl:for-each>
<UserID>
<xsl:value-of select="'WMUser'" />
</UserID>
<xsl:for-each select="n:DataArea/n:ReceiveDelivery/n:ReceiveDeliveryHeader/n:WarehouseLocation/n:ID">
<WarehouseID>
<xsl:value-of select="substring-before(string(.), '-W')" />
</WarehouseID>
</xsl:for-each>
</Header00>
<xsl:for-each select="n:DataArea/n:ReceiveDelivery/n:ReceiveDeliveryItem">
<Detail01>
<xsl:for-each select="$var2_SyncReceiveDelivery/n:DataArea/n:Sync/n:AccountingEntityID">
<Scanneddata1>
<xsl:value-of select="string(.)" />
</Scanneddata1>
</xsl:for-each>
</Detail01>
</xsl:for-each>
<xsl:for-each select="n:DataArea/n:ReceiveDelivery">
<xsl:variable name="var22_ReceiveDelivery" select="." />
<xsl:for-each select="n:ReceiveDeliveryItem">
<Detail02>
<xsl:for-each select="$var22_ReceiveDelivery/n:ReceiveDeliveryHeader/n:DocumentReference/n:DocumentID">
<xsl:variable name="var26_DocumentID" select="." />
<xsl:if test="$var26_DocumentID/n:ID/#location">
<Scanneddata2>
<xsl:value-of select="substring-before(string(n:ID/#location), '-B')" />
</Scanneddata2>
</xsl:if>
</xsl:for-each>
</Detail02>
</xsl:for-each>
</xsl:for-each>
<xsl:for-each select="n:DataArea/n:ReceiveDelivery">
<xsl:variable name="var28_ReceiveDelivery" select="." />
<xsl:for-each select="n:ReceiveDeliveryItem">
<Detail03>
<xsl:for-each select="$var28_ReceiveDelivery/n:ReceiveDeliveryHeader/n:DocumentReference/n:DocumentID">
<Scanneddata3>
<xsl:value-of select="string(n:ID)" />
</Scanneddata3>
</xsl:for-each>
</Detail03>
</xsl:for-each>
</xsl:for-each>
<xsl:for-each select="n:DataArea/n:ReceiveDelivery/n:ReceiveDeliveryItem">
<Detail04>
<xsl:for-each select="n:LineNumber">
<Scanneddata4>
<xsl:value-of select="string(.)" />
</Scanneddata4>
</xsl:for-each>
</Detail04>
</xsl:for-each>
<xsl:for-each select="n:DataArea/n:ReceiveDelivery/n:ReceiveDeliveryItem">
<xsl:variable name="var38_ReceiveDeliveryItem" select="." />
<Detail05>
<xsl:variable name="var40_map_select_SerializedLot">
<xsl:if test="string((n:SerializedLot/n:Lot/n:LotIDs/n:ID) = (n:SerializedLot/n:Lot/n:LotIDs/n:ID)) != 'false'">
<xsl:value-of select="'1'" />
</xsl:if>
</xsl:variable>
<xsl:variable name="var48_">
<xsl:choose>
<xsl:when test="string(boolean(string($var40_map_select_SerializedLot))) != 'false'">
<xsl:variable name="var45_map_select_SerializedLot">
<xsl:for-each select="n:SerializedLot/n:Lot/n:LotIDs/n:ID">
<xsl:value-of select="string(.)" />
</xsl:for-each>
</xsl:variable>
<xsl:variable name="var41_map_select_SerializedLot">
<xsl:if test="string((string($var45_map_select_SerializedLot)) = (string($var45_map_select_SerializedLot))) != 'false'">
<xsl:value-of select="'1'" />
</xsl:if>
</xsl:variable>
<xsl:if test="string(boolean(string($var41_map_select_SerializedLot))) != 'false'">
<xsl:variable name="var42_map_select_SerializedLot">
<xsl:for-each select="n:SerializedLot/n:Lot/n:LotIDs/n:ID">
<xsl:value-of select="string(.)" />
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="string($var42_map_select_SerializedLot)" />
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="' '" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<Scanneddata5>
<xsl:copy-of select="$var48_" />
</Scanneddata5>
</Detail05>
</xsl:for-each>
<xsl:for-each select="n:DataArea/n:ReceiveDelivery/n:ReceiveDeliveryItem">
<Detail06>
<xsl:for-each select="n:HoldCodes/n:Code">
<Scanneddata6>
<xsl:choose>
<xsl:when test="string((' ' != string(.))) != 'false'">
<xsl:value-of select="'Hold'" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'Inventory'" />
</xsl:otherwise>
</xsl:choose>
</Scanneddata6>
</xsl:for-each>
</Detail06>
</xsl:for-each>
<Detail07>
<xsl:for-each select="n:DataArea/n:ReceiveDelivery/n:ReceiveDeliveryHeader/n:ReceivedDateTime">
<Scanneddata7>
<xsl:value-of select="string(.)" />
</Scanneddata7>
</xsl:for-each>
</Detail07>
<xsl:for-each select="n:DataArea/n:ReceiveDelivery/n:ReceiveDeliveryItem">
<Detail11>
<xsl:for-each select="n:ReceivedQuantity">
<Scanneddata11>
<xsl:value-of select="number(string(.))" />
</Scanneddata11>
</xsl:for-each>
</Detail11>
</xsl:for-each>
</xsl:for-each>
</AsyncBarcode>
</xsl:template>
</xsl:stylesheet>
Below is the input I am receiving:
<SyncReceiveDelivery xmlns="http://schema.infor.com/InforOAGIS/2" releaseID="9.2" versionID="2.8.0">
<ApplicationArea>
<Sender>
<LogicalID>lid://</LogicalID>
<ComponentID>Warehouse Management</ComponentID>
<ReferenceID accountingEntity="01" location="RS01-W">0000058141</ReferenceID>
</Sender>
<CreationDateTime>2015-03-31T20:08:16Z</CreationDateTime>
<BODID>infor-nid:infor:01:RS01-W:0000002445:62883?ReceiveDelivery&verb=Sync</BODID>
</ApplicationArea>
<DataArea>
<Sync>
<TenantID>infor</TenantID>
<AccountingEntityID>01</AccountingEntityID>
<LocationID accountingEntity="01">RS01-W</LocationID>
<ActionCriteria>
<ActionExpression actionCode="Add" />
</ActionCriteria>
</Sync>
<ReceiveDelivery>
<ReceiveDeliveryHeader>
<DocumentID>
<ID accountingEntity="01" location="RS01-W" variationID="62883">0000002445</ID>
</DocumentID>
<LastModificationDateTime>2015-03-31T20:08:12Z</LastModificationDateTime>
<DocumentDateTime>2015-03-31T20:08:12Z</DocumentDateTime>
<DocumentReference type="CustomerReturn">
<DocumentID>
<ID accountingEntity="01" location="1323-B">930131</ID>
</DocumentID>
</DocumentReference>
<Status>
<Code listID="ReceiveDeliveryStatus">Received</Code>
</Status>
<WarehouseLocation>
<ID accountingEntity="01">RS01-W</ID>
<Name languageID="en-US">Power Packaging</Name>
<Address>
<AddressLine sequence="1">401 N. Main</AddressLine>
<CityName>Rosendale</CityName>
<CountrySubDivisionCode>WI</CountrySubDivisionCode>
<PostalCode listID="PostalCode">54974</PostalCode>
</Address>
</WarehouseLocation>
<ActualDeliveryDateTime>2015-03-31T17:31:46Z</ActualDeliveryDateTime>
<GrossWeightMeasure unitCode="LB">8120.4147</GrossWeightMeasure>
<TotalVolumeMeasure unitCode="CF">0</TotalVolumeMeasure>
<ShipFromParty>
<Location>
<ID>30155</ID>
<Name languageID="en-US">RS-IFP-USFS HOUSTON</Name>
<Address>
<AddressLine sequence="1">USFS HOUSTON</AddressLine>
<AddressLine sequence="2">111 ALIANT DRIVE</AddressLine>
<CityName>HOUSTON</CityName>
<CountrySubDivisionCode>TX</CountrySubDivisionCode>
<CountryCode>USA</CountryCode>
<PostalCode listID="PostalCode">77032</PostalCode>
</Address>
</Location>
</ShipFromParty>
<ReceivedDateTime>2015-03-31T20:08:12Z</ReceivedDateTime>
<DeliverToParty>
<Location>
<ID accountingEntity="01">RS01-W</ID>
<Name languageID="en-US">Power Packaging</Name>
<Address>
<AddressLine sequence="1">401 N. Main</AddressLine>
<CityName>Rosendale</CityName>
<CountrySubDivisionCode>WI</CountrySubDivisionCode>
<PostalCode listID="PostalCode">54974</PostalCode>
</Address>
</Location>
</DeliverToParty>
<ASNReference>
<DocumentID>
<ID accountingEntity="01" location="RS01-W">0000002445</ID>
</DocumentID>
</ASNReference>
</ReceiveDeliveryHeader>
<ReceiveDeliveryItem>
<ItemID>
<ID accountingEntity="01">200135-100250</ID>
</ItemID>
<ServiceIndicator>false</ServiceIndicator>
<Description languageID="en-US">Orchard Splash 12/25 fl oz Orange Gold 100</Description>
<Note languageID="en-US">1</Note>
<DocumentReference type="CustomerReturn">
<DocumentID>
<ID accountingEntity="01" location="1323-B">930131</ID>
</DocumentID>
<LineNumber>1</LineNumber>
</DocumentReference>
<PackingSlipQuantity unitCode="CS">0.0</PackingSlipQuantity>
<PackingSlipBaseUOMQuantity unitCode="CS">0.0</PackingSlipBaseUOMQuantity>
<ReceivedQuantity unitCode="CS">90.0</ReceivedQuantity>
<ReceivedBaseUOMQuantity unitCode="CS">90.0</ReceivedBaseUOMQuantity>
<ReturnedQuantity unitCode="CS">0.0</ReturnedQuantity>
<ReturnedBaseUOMQuantity unitCode="CS">0.0</ReturnedBaseUOMQuantity>
<SerializedLot>
<ItemQuantity unitCode="CS">90.0</ItemQuantity>
<ItemBaseUOMQuantity unitCode="CS">90.0</ItemBaseUOMQuantity>
<Lot>
<LotIDs>
<ID>RS1412107</ID>
</LotIDs>
<Quantity unitCode="CS">90.0</Quantity>
<BaseUOMQuantity unitCode="CS">90.0</BaseUOMQuantity>
</Lot>
</SerializedLot>
<LineNumber>1</LineNumber>
<HoldCodes>
<Code listID="Hold Reason Codes">HOLD</Code>
</HoldCodes>
<HoldCodes>
<Code listID="Hold Reason Codes">QCREQ</Code>
</HoldCodes>
<CountSequence>1</CountSequence>
</ReceiveDeliveryItem>
<ReceiveDeliveryItem>
<ItemID>
<ID accountingEntity="01">200135-100252</ID>
</ItemID>
<ServiceIndicator>false</ServiceIndicator>
<Description languageID="en-US">Orchard Hills 12/25 fl oz Orange 100</Description>
<Note languageID="en-US">2</Note>
<DocumentReference type="CustomerReturn">
<DocumentID>
<ID accountingEntity="01" location="1323-B">930131</ID>
</DocumentID>
<LineNumber>2</LineNumber>
</DocumentReference>
<PackingSlipQuantity unitCode="CS">0.0</PackingSlipQuantity>
<PackingSlipBaseUOMQuantity unitCode="CS">0.0</PackingSlipBaseUOMQuantity>
<ReceivedQuantity unitCode="CS">90.0</ReceivedQuantity>
<ReceivedBaseUOMQuantity unitCode="CS">90.0</ReceivedBaseUOMQuantity>
<ReturnedQuantity unitCode="CS">0.0</ReturnedQuantity>
<ReturnedBaseUOMQuantity unitCode="CS">0.0</ReturnedBaseUOMQuantity>
<SerializedLot>
<ItemQuantity unitCode="CS">90.0</ItemQuantity>
<ItemBaseUOMQuantity unitCode="CS">90.0</ItemBaseUOMQuantity>
<Lot>
<LotIDs>
<ID>RS141112</ID>
</LotIDs>
<Quantity unitCode="CS">90.0</Quantity>
<BaseUOMQuantity unitCode="CS">90.0</BaseUOMQuantity>
</Lot>
</SerializedLot>
<LineNumber>2</LineNumber>
<HoldCodes>
<Code listID="Hold Reason Codes">HOLD</Code>
</HoldCodes>
<HoldCodes>
<Code listID="Hold Reason Codes">QCREQ</Code>
</HoldCodes>
<CountSequence>1</CountSequence>
</ReceiveDeliveryItem>
<ReceiveDeliveryItem>
<ItemID>
<ID accountingEntity="01">200135-100252</ID>
</ItemID>
<ServiceIndicator>false</ServiceIndicator>
<Description languageID="en-US">Orchard Hills 12/25 fl oz Orange 100</Description>
<Note languageID="en-US">3</Note>
<DocumentReference type="CustomerReturn">
<DocumentID>
<ID accountingEntity="01" location="1323-B">930131</ID>
</DocumentID>
<LineNumber>3</LineNumber>
</DocumentReference>
<PackingSlipQuantity unitCode="CS">0.0</PackingSlipQuantity>
<PackingSlipBaseUOMQuantity unitCode="CS">0.0</PackingSlipBaseUOMQuantity>
<ReceivedQuantity unitCode="CS">90.0</ReceivedQuantity>
<ReceivedBaseUOMQuantity unitCode="CS">90.0</ReceivedBaseUOMQuantity>
<ReturnedQuantity unitCode="CS">0.0</ReturnedQuantity>
<ReturnedBaseUOMQuantity unitCode="CS">0.0</ReturnedBaseUOMQuantity>
<SerializedLot>
<ItemQuantity unitCode="CS">90.0</ItemQuantity>
<ItemBaseUOMQuantity unitCode="CS">90.0</ItemBaseUOMQuantity>
<Lot>
<LotIDs>
<ID>RS1412030</ID>
</LotIDs>
<Quantity unitCode="CS">90.0</Quantity>
<BaseUOMQuantity unitCode="CS">90.0</BaseUOMQuantity>
</Lot>
</SerializedLot>
<LineNumber>3</LineNumber>
<HoldCodes>
<Code listID="Hold Reason Codes">HOLD</Code>
</HoldCodes>
<HoldCodes>
<Code listID="Hold Reason Codes">QCREQ</Code>
</HoldCodes>
<CountSequence>1</CountSequence>
</ReceiveDeliveryItem>
</ReceiveDelivery>
</DataArea>
</SyncReceiveDelivery>
Finally, this is what I am expecting however I am getting duplicates values in Scannedata6 for the Detail06 section:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE AsyncBarcode SYSTEM "C:/InboundBODS/AsyncBarcode_Inbound.dtd">
<AsyncBarcode>
<Prefix>
<CompanyID>01</CompanyID>
<ExternalPartnerID>01</ExternalPartnerID>
<DocumentType>AsyncBarcode</DocumentType>
<DocumentNumber/>
<TransactionDirection>I</TransactionDirection>
<DateStamp>2015-03-31</DateStamp>
<TimeStamp>20:08:16</TimeStamp>
<ControlNumber/>
</Prefix>
<Header00>
<TransactionDefinitionKey>25</TransactionDefinitionKey>
<CompanyID0>01</CompanyID0>
<BranchID>1323</BranchID>
<UserID>WMUser</UserID>
<WarehouseID>RS01</WarehouseID>
</Header00>
<Detail01>
<Scanneddata1>01</Scanneddata1>
</Detail01>
<Detail01>
<Scanneddata1>01</Scanneddata1>
</Detail01>
<Detail01>
<Scanneddata1>01</Scanneddata1>
</Detail01>
<Detail02>
<Scanneddata2>1323</Scanneddata2>
</Detail02>
<Detail02>
<Scanneddata2>1323</Scanneddata2>
</Detail02>
<Detail02>
<Scanneddata2>1323</Scanneddata2>
</Detail02>
<Detail03>
<Scanneddata3>930131</Scanneddata3>
</Detail03>
<Detail03>
<Scanneddata3>930131</Scanneddata3>
</Detail03>
<Detail03>
<Scanneddata3>930131</Scanneddata3>
</Detail03>
<Detail04>
<Scanneddata4>1</Scanneddata4>
</Detail04>
<Detail04>
<Scanneddata4>2</Scanneddata4>
</Detail04>
<Detail04>
<Scanneddata4>3</Scanneddata4>
</Detail04>
<Detail05>
<Scanneddata5>RS1412107</Scanneddata5>
</Detail05>
<Detail05>
<Scanneddata5>RS141112</Scanneddata5>
</Detail05>
<Detail05>
<Scanneddata5>RS1412030</Scanneddata5>
</Detail05>
<Detail06>
<Scanneddata6>Hold</Scanneddata6>
</Detail06>
<Detail06>
<Scanneddata6>Hold</Scanneddata6>
</Detail06>
<Detail06>
<Scanneddata6>Hold</Scanneddata6>
</Detail06>
<Detail07>
<Scanneddata7>2015-03-31T20:08:12Z</Scanneddata7>
</Detail07>
<Detail11>
<Scanneddata11>90</Scanneddata11>
</Detail11>
<Detail11>
<Scanneddata11>90</Scanneddata11>
</Detail11>
<Detail11>
<Scanneddata11>90</Scanneddata11>
</Detail11>
</AsyncBarcode>

Was able to figure out what I needed to change. Change shown below:
<xsl:for-each select="n:DataArea/n:ReceiveDelivery/n:ReceiveDeliveryItem/n:HoldCodes[1]">
<Detail06>
<xsl:for-each select="n:Code[1]">
<Scanneddata6>
<xsl:choose>
<xsl:when test="string(('' != string(.))) != 'false'">
<xsl:value-of select="'Hold'" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'Inventory'" />
</xsl:otherwise>
</xsl:choose>
</Scanneddata6>
</xsl:for-each>
</Detail06>
</xsl:for-each>

Related

XSLT 1.0 Json Array [duplicate]

How would you convert JSON to XML?
Consider:
<sampleTag>
{
"Order": {
"InvestmentAccount": { "AccountNumber": "10" },
"Parcel": {
"Limit": "0",
"ExpiryDate": "1900-01-01T00:00:00",
"Asset": [
{
"Open": "25.15",
"High": "25.15",
"Low": "25.11",
"Close": "25.87"
}
{
"Open": "25.15",
"High": "25.15",
"Low": "25.11",
"Close": "25.87"
}]
},
"OrderDate": "2012-10-11T21:46:03.6489906+11:00",
}
}
</sampleTag>
After transformation, the document is as follows:
<Order>
<InvestmentAccount>
<AccountNumber>10</AccountNumber>
</InvestmentAccount>
<Parcel>
<Limit>0</Limit>
<ExpiryDate>1900-01-01T00:00:00</ExpiryDate>
<Asset>
<Open>25.15</Open>
<High>25.15</High>
<Low>25.11</Low>
<Close>25.87</Close>
</Asset>
<Asset>
<Open>25.15</Open>
<High>25.15</High>
<Low>25.11</Low>
<Close>25.87</Close>
</Asset>
</Parcel>
<OrderDate>2012-10-11T21:46:03.6489906+11:00</OrderDate>
</Order>
My work on JSON parsing doesn't cover the full JSON grammar.
And the task of "translating" any JSON document to an XML document doesn't have a solution. There are JSON constructs, which cannot be translated to XML without defining additional conventions and introducing additional elements -- so the final XML structure isn't a true and natural representation of the original JSON object.
In XSLT 3.0 there is a function to parse any JSON object -- parse-json() -- to a map -- a new data type introduced in XSLT 3.0. Read about this here:
http://www.w3.org/TR/xslt-30/#json
Actually, it is not that hard. The way to approach it is to examine the syntax of jason, and view each production like it was a template. I was just about to write a solution, when I considered the possibility that the OP forgot to google for pre-existing solutions. I searched and lo and behold ....
http://dnovatchev.wordpress.com/2007/07/05/transforming-json/
UPDATE
Here is a JSon to XML converter. But it only works on a subset of json. Hopefully, the subset is broad enough for your particular needs. In particular the limitations are:
The only simple type supported is string. No integer, boolean or null.
Json object names must be valid xml element names.
No escape codes permitted inside string values. This means that you cant transport values that include, for instance, the " character (without rolling your own encoding layer).
This XSLT 1.0 style-sheet...*
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx"
xmlns:exsl="http://exslt.org/common"
xmlns:so="http://stackoverflow.com/questions/13007280"
exclude-result-prefixes="xsl xs json so exsl">
<xsl:output indent="yes" encoding="UTF-8" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:variable name="quot" select="'"'" />
<xsl:template match="/*">
<xsl:variable name="t1">
<xsl:call-template name="object">
<xsl:with-param name="json-in" select="." />
</xsl:call-template>
</xsl:variable>
<xsl:apply-templates select="exsl:node-set($t1)/so:output/*" mode="copy-sans-namespace" />
</xsl:template>
<xsl:template match="*" mode="copy-sans-namespace">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="#*"/>
<xsl:apply-templates mode="copy-sans-namespace" />
</xsl:element>
</xsl:template>
<xsl:template name="field">
<!-- Input like: "Open": "25.15" bla -->
<!-- output like: <so:output><Open>25.15</Open></so:output> <so:extra>bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:variable name="field-name" select="substring-before(substring-after($json-in,$quot),$quot)" />
<xsl:variable name="remainder" select="substring-after($json-in,':')" />
<xsl:call-template name="value">
<xsl:with-param name="json-in" select="$remainder" />
<xsl:with-param name="parent-ele" select="$field-name" />
</xsl:call-template>
</xsl:template>
<xsl:template name="fields">
<!-- Input like: "Open": "25.15" , "High": "25.15" } bla -->
<!-- output like: <so:output><Open>25.15</Open><High>25.15</High></so:output> <so:extra>} bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:variable name="n" select="normalize-space($json-in)" />
<xsl:choose>
<xsl:when test="substring($n,1,1) = $quot">
<xsl:variable name="t1">
<xsl:call-template name="field">
<xsl:with-param name="json-in" select="$n" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="t2" select="normalize-space( exsl:node-set($t1)/so:extra) " />
<xsl:variable name="t3">
<xsl:choose>
<xsl:when test="substring($t2,1,1)=','">
<xsl:call-template name="fields">
<xsl:with-param name="json-in" select="substring-after($t2,',')" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$t2">
<so:extra><xsl:value-of select="$t2" /></so:extra>
</xsl:when>
</xsl:choose>
</xsl:variable>
<so:output>
<xsl:copy-of select="exsl:node-set($t1)/so:output/* | exsl:node-set($t3)/so:output/*" />
</so:output>
<xsl:copy-of select="exsl:node-set($t3)/so:extra" />
</xsl:when>
<xsl:when test="$n">
<so:extra><xsl:value-of select="$n" /></so:extra>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="object">
<!-- Input like: { X } bla -->
<!-- output like: <so:output>fields(X)</so:output> <so:extra>bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" select="''" />
<xsl:variable name="t1" select="normalize-space(substring-after($json-in,'{'))" />
<xsl:variable name="t2">
<xsl:call-template name="fields">
<xsl:with-param name="json-in" select="$t1" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="t3" select="normalize-space(substring-after( exsl:node-set($t2)/so:extra, '}'))" />
<so:output>
<xsl:choose>
<xsl:when test="$parent-ele">
<xsl:element name="{$parent-ele}">
<xsl:copy-of select="exsl:node-set($t2)/so:output/node()" />
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="exsl:node-set($t2)/so:output/node()" />
</xsl:otherwise>
</xsl:choose>
</so:output>
<xsl:if test="$t3">
<so:extra><xsl:value-of select="$t3" /></so:extra>
</xsl:if>
</xsl:template>
<xsl:template name="objects">
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="n" select="normalize-space($json-in)" />
<xsl:choose>
<xsl:when test="substring($n,1,1) = '{'">
<xsl:variable name="t1">
<xsl:call-template name="object">
<xsl:with-param name="json-in" select="$n" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="t2" select="normalize-space( exsl:node-set($t1)/so:extra) " />
<xsl:variable name="t3">
<xsl:choose>
<xsl:when test="substring($t2,1,1)='{'">
<xsl:call-template name="objects">
<xsl:with-param name="json-in" select="$t2" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$t2">
<so:extra><xsl:value-of select="$t2" /></so:extra>
</xsl:when>
</xsl:choose>
</xsl:variable>
<so:output>
<xsl:copy-of select="exsl:node-set($t1)/so:output/* | exsl:node-set($t3)/so:output/*" />
</so:output>
<xsl:copy-of select="exsl:node-set($t3)/so:extra" />
</xsl:when>
<xsl:when test="$n">
<so:extra><xsl:value-of select="$n" /></so:extra>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="array">
<!-- Input like: [ X1 X2 ] bla -->
<!-- output like: <so:output><Y>X1</Y><Y>X2</Y></so:output> <so:extra>}bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="t1" select="normalize-space(substring-after($json-in,'['))" />
<xsl:variable name="t2">
<xsl:call-template name="objects">
<xsl:with-param name="json-in" select="$t1" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="t3" select="normalize-space(substring-after( exsl:node-set($t2)/so:extra, ']'))" />
<xsl:copy-of select="exsl:node-set($t2)/so:output" />
<xsl:if test="$t3">
<so:extra><xsl:value-of select="$t3" /></so:extra>
</xsl:if>
</xsl:template>
<xsl:template name="value">
<!-- Input like either array, object or string -->
<!-- output like either array, object or string -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="first-letter" select="substring(normalize-space($json-in),1,1)" />
<xsl:choose>
<xsl:when test="$first-letter='{'">
<xsl:call-template name="object">
<xsl:with-param name="json-in" select="$json-in" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$first-letter='['">
<xsl:call-template name="array">
<xsl:with-param name="json-in" select="$json-in" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$first-letter=$quot">
<xsl:call-template name="string">
<xsl:with-param name="json-in" select="$json-in" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<so:output>ERROR</so:output>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="string">
<!-- Input like: "X" bla -->
<!-- output like: <so:output><Y>X</Y></so:output> <so:extra>bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="value" select="substring-before(substring-after($json-in,$quot),$quot)" />
<xsl:variable name="remainder" select="normalize-space(substring-after(substring-after($json-in,$quot),$quot))" />
<so:output>
<xsl:element name="{$parent-ele}">
<xsl:value-of select="$value" />
</xsl:element>
</so:output>
<xsl:if test="$remainder">
<so:extra><xsl:value-of select="$remainder" /></so:extra>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
...applied to this input (modified from OP supplied to remove an extraneous comma)...
<sampleTag>
{
"Order": {
"InvestmentAccount": { "AccountNumber": "10" },
"Parcel": {
"Limit": "0",
"ExpiryDate": "1900-01-01T00:00:00",
"Asset": [
{
"Open": "25.15",
"High": "25.15",
"Low": "25.11",
"Close": "25.87"
}
{
"Open": "25.15",
"High": "25.15",
"Low": "25.11",
"Close": "25.87"
}]
},
"OrderDate": "2012-10-11T21:46:03.6489906+11:00"
}
}
</sampleTag>
..yields...
<Order>
<InvestmentAccount>
<AccountNumber>10</AccountNumber>
</InvestmentAccount>
<Parcel>
<Limit>0</Limit>
<ExpiryDate>1900-01-01T00:00:00</ExpiryDate>
<Asset>
<Open>25.15</Open>
<High>25.15</High>
<Low>25.11</Low>
<Close>25.87</Close>
</Asset>
<Asset>
<Open>25.15</Open>
<High>25.15</High>
<Low>25.11</Low>
<Close>25.87</Close>
</Asset>
</Parcel>
<OrderDate>2012-10-11T21:46:03.6489906+11:00</OrderDate>
</Order>
I tweaked Sean B. Durkin's template a bit and thought I'd share.
Updates include:
Support for numbers
Support for booleans
Fix for object array elements separated by a comma (per JSON spec)
Non-update changes:
Array elements are displayed in their own XML elements with the element name as the object key suffixed with _element
Still not supported:
Escaped characters (quotes) in strings
Here's the template:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx"
xmlns:exsl="http://exslt.org/common"
xmlns:so="http://stackoverflow.com/questions/13007280"
exclude-result-prefixes="xsl xs json so exsl">
<xsl:output indent="yes" encoding="UTF-8" />
<xsl:strip-space elements="*" />
<xsl:variable name="quot" select="'"'" />
<xsl:variable name="numbers" select="'0123456789'"/>
<xsl:variable name="booleans" select="'tf'"/>
<xsl:template match="/*">
<xsl:variable name="t1">
<xsl:call-template name="object">
<xsl:with-param name="json-in" select="." />
</xsl:call-template>
</xsl:variable>
<xsl:apply-templates select="exsl:node-set($t1)/so:output/*" mode="copy-sans-namespace" />
</xsl:template>
<xsl:template match="*" mode="copy-sans-namespace">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="#*"/>
<xsl:apply-templates mode="copy-sans-namespace" />
</xsl:element>
</xsl:template>
<xsl:template name="field">
<!-- Input like: "Open": "25.15" bla -->
<!-- output like: <so:output><Open>25.15</Open></so:output> <so:extra>bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:variable name="field-name" select="substring-before(substring-after($json-in,$quot),$quot)" />
<xsl:variable name="remainder" select="substring-after($json-in,':')" />
<xsl:call-template name="value">
<xsl:with-param name="json-in" select="$remainder" />
<xsl:with-param name="parent-ele" select="$field-name" />
</xsl:call-template>
</xsl:template>
<xsl:template name="fields">
<!-- Input like: "Open": "25.15" , "High": "25.15" } bla -->
<!-- output like: <so:output><Open>25.15</Open><High>25.15</High></so:output> <so:extra>} bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:variable name="n" select="normalize-space($json-in)" />
<xsl:choose>
<xsl:when test="substring($n,1,1) = $quot">
<xsl:variable name="t1">
<xsl:call-template name="field">
<xsl:with-param name="json-in" select="$n" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="t2" select="normalize-space( exsl:node-set($t1)/so:extra) " />
<xsl:variable name="t3">
<xsl:choose>
<xsl:when test="substring($t2,1,1)=','">
<xsl:call-template name="fields">
<xsl:with-param name="json-in" select="substring-after($t2,',')" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$t2">
<so:extra><xsl:value-of select="$t2" /></so:extra>
</xsl:when>
</xsl:choose>
</xsl:variable>
<so:output>
<xsl:copy-of select="exsl:node-set($t1)/so:output/* | exsl:node-set($t3)/so:output/*" />
</so:output>
<xsl:copy-of select="exsl:node-set($t3)/so:extra" />
</xsl:when>
<xsl:when test="$n">
<so:extra><xsl:value-of select="$n" /></so:extra>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="object">
<!-- Input like: { X } bla -->
<!-- output like: <so:output>fields(X)</so:output> <so:extra>bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" select="''" />
<xsl:variable name="t1" select="normalize-space(substring-after($json-in,'{'))" />
<xsl:variable name="t2">
<xsl:call-template name="fields">
<xsl:with-param name="json-in" select="$t1" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="t3" select="normalize-space(substring-after( exsl:node-set($t2)/so:extra, '}'))" />
<so:output>
<xsl:choose>
<xsl:when test="$parent-ele">
<xsl:element name="{$parent-ele}">
<xsl:copy-of select="exsl:node-set($t2)/so:output/node()" />
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="exsl:node-set($t2)/so:output/node()" />
</xsl:otherwise>
</xsl:choose>
</so:output>
<xsl:if test="$t3">
<so:extra><xsl:value-of select="$t3" /></so:extra>
</xsl:if>
</xsl:template>
<xsl:template name="objects">
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="n" select="normalize-space($json-in)" />
<xsl:choose>
<xsl:when test="substring($n,1,1) = '{'">
<xsl:variable name="t1">
<xsl:call-template name="object">
<xsl:with-param name="json-in" select="$n" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="t2" select="normalize-space( exsl:node-set($t1)/so:extra) " />
<xsl:variable name="t3">
<xsl:choose>
<xsl:when test="substring($t2,1,1)='{'">
<xsl:call-template name="objects">
<xsl:with-param name="json-in" select="$t2" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:when>
<xsl:when test="substring($t2,1,1)=',' and substring(normalize-space(substring-after($t2,',')),1,1)='{'">
<xsl:call-template name="objects">
<xsl:with-param name="json-in" select="normalize-space(substring-after($t2,','))" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$t2">
<so:extra><xsl:value-of select="$t2" /></so:extra>
</xsl:when>
</xsl:choose>
</xsl:variable>
<so:output>
<xsl:copy-of select="exsl:node-set($t1)/so:output/* | exsl:node-set($t3)/so:output/*" />
</so:output>
<xsl:copy-of select="exsl:node-set($t3)/so:extra" />
</xsl:when>
<xsl:when test="$n">
<so:extra><xsl:value-of select="$n" /></so:extra>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="array">
<!-- Input like: [ X1 X2 ] bla -->
<!-- output like: <so:output><Y>X1</Y><Y>X2</Y></so:output> <so:extra>}bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="t1" select="normalize-space(substring-after($json-in,'['))" />
<xsl:variable name="t2">
<xsl:call-template name="objects">
<xsl:with-param name="json-in" select="$t1" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="t3">
<xsl:choose>
<xsl:when test="contains(substring-before(exsl:node-set($t2)/so:extra,']'),',')">
<xsl:value-of select="normalize-space(substring-after(exsl:node-set($t2)/so:extra,','))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="normalize-space(substring-after(exsl:node-set($t2)/so:extra,']'))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="t4">
<xsl:element name="{$parent-ele}">
<xsl:for-each select="$t2/so:output/*[local-name(.)=$parent-ele]">
<xsl:variable name="self" select="."/>
<xsl:variable name="tempResult">
<xsl:element name="{concat($parent-ele,'_element')}">
<xsl:copy-of select="exsl:node-set($self/*)" />
</xsl:element>
</xsl:variable>
<xsl:copy-of select="exsl:node-set($tempResult)"/>
</xsl:for-each>
</xsl:element>
</xsl:variable>
<xsl:variable name="t5" select="exsl:node-set($t4)"/>
<so:output>
<xsl:copy-of select="$t5"/>
</so:output>
<xsl:if test="$t3">
<so:extra><xsl:value-of select="$t3" /></so:extra>
</xsl:if>
</xsl:template>
<xsl:template name="value">
<!-- Input like either array, object or string -->
<!-- output like either array, object or string -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="first-letter" select="substring(normalize-space($json-in),1,1)" />
<xsl:choose>
<xsl:when test="$first-letter='{'">
<xsl:call-template name="object">
<xsl:with-param name="json-in" select="$json-in" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$first-letter='['">
<xsl:call-template name="array">
<xsl:with-param name="json-in" select="$json-in" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$first-letter=$quot">
<xsl:call-template name="string">
<xsl:with-param name="json-in" select="$json-in" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($numbers,$first-letter)">
<xsl:call-template name="number">
<xsl:with-param name="json-in" select="$json-in" />
<xsl:with-param name="parent-ele" select="$parent-ele"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($booleans,$first-letter)">
<xsl:call-template name="boolean">
<xsl:with-param name="json-in" select="$json-in" />
<xsl:with-param name="parent-ele" select="$parent-ele"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<so:output>ERROR</so:output>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="string">
<!-- Input like: "X" bla -->
<!-- output like: <so:output><Y>X</Y></so:output> <so:extra>bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="value" select="substring-before(substring-after($json-in,$quot),$quot)" />
<xsl:variable name="remainder" select="normalize-space(substring-after(substring-after($json-in,$quot),$quot))" />
<so:output>
<xsl:element name="{$parent-ele}">
<xsl:value-of select="$value" />
</xsl:element>
</so:output>
<xsl:if test="$remainder">
<so:extra><xsl:value-of select="$remainder" /></so:extra>
</xsl:if>
</xsl:template>
<xsl:template name="number">
<!-- Input like: "X" bla -->
<!-- output like: <so:output><Y>X</Y></so:output> <so:extra>bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="value">
<xsl:choose>
<xsl:when test="contains(substring-before($json-in,','),'}')">
<xsl:value-of select="normalize-space(substring-before($json-in,'}'))"/>
</xsl:when>
<xsl:when test="contains(substring-before($json-in,','),']')">
<xsl:value-of select="normalize-space(substring-before($json-in,']'))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="normalize-space(substring-before($json-in,','))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="remainder">
<xsl:choose>
<xsl:when test="contains(substring-before($json-in,','),'}')">
<xsl:value-of select="concat('}',normalize-space(substring-after($json-in,'}')))"/>
</xsl:when>
<xsl:when test="contains(substring-before($json-in,','),']')">
<xsl:value-of select="concat(']',normalize-space(substring-after($json-in,']')))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(',',normalize-space(substring-after($json-in,',')))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<so:output>
<xsl:element name="{$parent-ele}">
<xsl:value-of select="$value" />
</xsl:element>
</so:output>
<xsl:if test="$remainder">
<so:extra><xsl:value-of select="$remainder" /></so:extra>
</xsl:if>
</xsl:template>
<xsl:template name="boolean">
<!-- Input like: "X" bla -->
<!-- output like: <so:output><Y>X</Y></so:output> <so:extra>bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="value">
<xsl:choose>
<xsl:when test="contains(substring-before($json-in,','),'}')">
<xsl:value-of select="normalize-space(substring-before($json-in,'}'))"/>
</xsl:when>
<xsl:when test="contains(substring-before($json-in,','),']')">
<xsl:value-of select="normalize-space(substring-before($json-in,']'))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="normalize-space(substring-before($json-in,','))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="remainder">
<xsl:choose>
<xsl:when test="contains(substring-before($json-in,','),'}')">
<xsl:value-of select="concat('}',normalize-space(substring-after($json-in,'}')))"/>
</xsl:when>
<xsl:when test="contains(substring-before($json-in,','),']')">
<xsl:value-of select="concat(']',normalize-space(substring-after($json-in,']')))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(',',normalize-space(substring-after($json-in,',')))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<so:output>
<xsl:element name="{$parent-ele}">
<xsl:value-of select="$value" />
</xsl:element>
</so:output>
<xsl:if test="$remainder">
<so:extra><xsl:value-of select="$remainder" /></so:extra>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
So with this (adjusted) input:
<?xml version="1.0" encoding="UTF-8"?>
<sampleTag><![CDATA[
{
"Order": {
"InvestmentAccount": { "AccountNumber": "10" },
"Parcel": {
"Limit": 0,
"ExpiryDate": "1900-01-01T00:00:00",
"valid": true,
"Asset": [
{
"Open": 25.15,
"High": 25.15,
"Low": 25.11,
"Close": 25.87
},
{
"Open": 25.15,
"High": 25.15,
"Low": 25.11,
"Close": 25.87
}
]
},
"OrderDate": "2012-10-11T21:46:03.6489906+11:00"
}
}
]]></sampleTag>
I get this output:
<?xml version="1.0" encoding="UTF-8"?>
<Order>
<InvestmentAccount>
<AccountNumber>10</AccountNumber>
</InvestmentAccount>
<Parcel>
<Limit>0</Limit>
<ExpiryDate>1900-01-01T00:00:00</ExpiryDate>
<valid>true</valid>
<Asset>
<Asset_element>
<Open>25.15</Open>
<High>25.15</High>
<Low>25.11</Low>
<Close>25.87</Close>
</Asset_element>
<Asset_element>
<Open>25.15</Open>
<High>25.15</High>
<Low>25.11</Low>
<Close>25.87</Close>
</Asset_element>
</Asset>
</Parcel>
<OrderDate>2012-10-11T21:46:03.6489906+11:00</OrderDate>
</Order>
Updating Samuel Murphy answer.
Updates include:
Support for null
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx"
xmlns:exsl="http://exslt.org/common"
xmlns:so="http://stackoverflow.com/questions/13007280"
exclude-result-prefixes="xsl xs json so exsl">
<xsl:output indent="yes" encoding="UTF-8" />
<xsl:strip-space elements="*" />
<xsl:variable name="quot" select="'"'" />
<xsl:variable name="numbers" select="'0123456789'"/>
<xsl:variable name="booleans" select="'tf'"/>
<xsl:variable name="nulls" select="'n'"/>
<xsl:template match="/*">
<xsl:variable name="t1">
<xsl:call-template name="object">
<xsl:with-param name="json-in" select="." />
</xsl:call-template>
</xsl:variable>
<xsl:apply-templates select="exsl:node-set($t1)/so:output/*" mode="copy-sans-namespace" />
</xsl:template>
<xsl:template match="*" mode="copy-sans-namespace">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="#*"/>
<xsl:apply-templates mode="copy-sans-namespace" />
</xsl:element>
</xsl:template>
<xsl:template name="field">
<!-- Input like: "Open": "25.15" bla -->
<!-- output like: <so:output><Open>25.15</Open></so:output> <so:extra>bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:variable name="field-name" select="substring-before(substring-after($json-in,$quot),$quot)" />
<xsl:variable name="remainder" select="substring-after($json-in,':')" />
<xsl:call-template name="value">
<xsl:with-param name="json-in" select="$remainder" />
<xsl:with-param name="parent-ele" select="$field-name" />
</xsl:call-template>
</xsl:template>
<xsl:template name="fields">
<!-- Input like: "Open": "25.15" , "High": "25.15" } bla -->
<!-- output like: <so:output><Open>25.15</Open><High>25.15</High></so:output> <so:extra>} bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:variable name="n" select="normalize-space($json-in)" />
<xsl:choose>
<xsl:when test="substring($n,1,1) = $quot">
<xsl:variable name="t1">
<xsl:call-template name="field">
<xsl:with-param name="json-in" select="$n" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="t2" select="normalize-space( exsl:node-set($t1)/so:extra) " />
<xsl:variable name="t3">
<xsl:choose>
<xsl:when test="substring($t2,1,1)=','">
<xsl:call-template name="fields">
<xsl:with-param name="json-in" select="substring-after($t2,',')" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$t2">
<so:extra><xsl:value-of select="$t2" /></so:extra>
</xsl:when>
</xsl:choose>
</xsl:variable>
<so:output>
<xsl:copy-of select="exsl:node-set($t1)/so:output/* | exsl:node-set($t3)/so:output/*" />
</so:output>
<xsl:copy-of select="exsl:node-set($t3)/so:extra" />
</xsl:when>
<xsl:when test="$n">
<so:extra><xsl:value-of select="$n" /></so:extra>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="object">
<!-- Input like: { X } bla -->
<!-- output like: <so:output>fields(X)</so:output> <so:extra>bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" select="''" />
<xsl:variable name="t1" select="normalize-space(substring-after($json-in,'{'))" />
<xsl:variable name="t2">
<xsl:call-template name="fields">
<xsl:with-param name="json-in" select="$t1" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="t3" select="normalize-space(substring-after( exsl:node-set($t2)/so:extra, '}'))" />
<so:output>
<xsl:choose>
<xsl:when test="$parent-ele">
<xsl:element name="{$parent-ele}">
<xsl:copy-of select="exsl:node-set($t2)/so:output/node()" />
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="exsl:node-set($t2)/so:output/node()" />
</xsl:otherwise>
</xsl:choose>
</so:output>
<xsl:if test="$t3">
<so:extra><xsl:value-of select="$t3" /></so:extra>
</xsl:if>
</xsl:template>
<xsl:template name="objects">
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="n" select="normalize-space($json-in)" />
<xsl:choose>
<xsl:when test="substring($n,1,1) = '{'">
<xsl:variable name="t1">
<xsl:call-template name="object">
<xsl:with-param name="json-in" select="$n" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="t2" select="normalize-space( exsl:node-set($t1)/so:extra) " />
<xsl:variable name="t3">
<xsl:choose>
<xsl:when test="substring($t2,1,1)='{'">
<xsl:call-template name="objects">
<xsl:with-param name="json-in" select="$t2" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:when>
<xsl:when test="substring($t2,1,1)=',' and substring(normalize-space(substring-after($t2,',')),1,1)='{'">
<xsl:call-template name="objects">
<xsl:with-param name="json-in" select="normalize-space(substring-after($t2,','))" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$t2">
<so:extra><xsl:value-of select="$t2" /></so:extra>
</xsl:when>
</xsl:choose>
</xsl:variable>
<so:output>
<xsl:copy-of select="exsl:node-set($t1)/so:output/* | exsl:node-set($t3)/so:output/*" />
</so:output>
<xsl:copy-of select="exsl:node-set($t3)/so:extra" />
</xsl:when>
<xsl:when test="$n">
<so:extra><xsl:value-of select="$n" /></so:extra>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="array">
<!-- Input like: [ X1 X2 ] bla -->
<!-- output like: <so:output><Y>X1</Y><Y>X2</Y></so:output> <so:extra>}bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="t1" select="normalize-space(substring-after($json-in,'['))" />
<xsl:variable name="t2">
<xsl:call-template name="objects">
<xsl:with-param name="json-in" select="$t1" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="t3">
<xsl:choose>
<xsl:when test="contains(substring-before(exsl:node-set($t2)/so:extra,']'),',')">
<xsl:value-of select="normalize-space(substring-after(exsl:node-set($t2)/so:extra,','))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="normalize-space(substring-after(exsl:node-set($t2)/so:extra,']'))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="t4">
<xsl:element name="{$parent-ele}">
<xsl:for-each select="$t2/so:output/*[local-name(.)=$parent-ele]">
<xsl:variable name="self" select="."/>
<xsl:variable name="tempResult">
<xsl:element name="{concat($parent-ele,'_element')}">
<xsl:copy-of select="exsl:node-set($self/*)" />
</xsl:element>
</xsl:variable>
<xsl:copy-of select="exsl:node-set($tempResult)"/>
</xsl:for-each>
</xsl:element>
</xsl:variable>
<xsl:variable name="t5" select="exsl:node-set($t4)"/>
<so:output>
<xsl:copy-of select="$t5"/>
</so:output>
<xsl:if test="$t3">
<so:extra><xsl:value-of select="$t3" /></so:extra>
</xsl:if>
</xsl:template>
<xsl:template name="value">
<!-- Input like either array, object or string -->
<!-- output like either array, object or string -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="first-letter" select="substring(normalize-space($json-in),1,1)" />
<xsl:choose>
<xsl:when test="$first-letter='{'">
<xsl:call-template name="object">
<xsl:with-param name="json-in" select="$json-in" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$first-letter='['">
<xsl:call-template name="array">
<xsl:with-param name="json-in" select="$json-in" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$first-letter=$quot">
<xsl:call-template name="string">
<xsl:with-param name="json-in" select="$json-in" />
<xsl:with-param name="parent-ele" select="$parent-ele" />
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($numbers,$first-letter)">
<xsl:call-template name="number">
<xsl:with-param name="json-in" select="$json-in" />
<xsl:with-param name="parent-ele" select="$parent-ele"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($booleans,$first-letter)">
<xsl:call-template name="boolean">
<xsl:with-param name="json-in" select="$json-in" />
<xsl:with-param name="parent-ele" select="$parent-ele"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($nulls,$first-letter)">
<xsl:call-template name="boolean">
<xsl:with-param name="json-in" select="$json-in" />
<xsl:with-param name="parent-ele" select="$parent-ele"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<so:output>ERROR</so:output>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="string">
<!-- Input like: "X" bla -->
<!-- output like: <so:output><Y>X</Y></so:output> <so:extra>bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="value" select="substring-before(substring-after($json-in,$quot),$quot)" />
<xsl:variable name="remainder" select="normalize-space(substring-after(substring-after($json-in,$quot),$quot))" />
<so:output>
<xsl:element name="{$parent-ele}">
<xsl:value-of select="$value" />
</xsl:element>
</so:output>
<xsl:if test="$remainder">
<so:extra><xsl:value-of select="$remainder" /></so:extra>
</xsl:if>
</xsl:template>
<xsl:template name="number">
<!-- Input like: "X" bla -->
<!-- output like: <so:output><Y>X</Y></so:output> <so:extra>bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="value">
<xsl:choose>
<xsl:when test="contains(substring-before($json-in,','),'}')">
<xsl:value-of select="normalize-space(substring-before($json-in,'}'))"/>
</xsl:when>
<xsl:when test="contains(substring-before($json-in,','),']')">
<xsl:value-of select="normalize-space(substring-before($json-in,']'))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="normalize-space(substring-before($json-in,','))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="remainder">
<xsl:choose>
<xsl:when test="contains(substring-before($json-in,','),'}')">
<xsl:value-of select="concat('}',normalize-space(substring-after($json-in,'}')))"/>
</xsl:when>
<xsl:when test="contains(substring-before($json-in,','),']')">
<xsl:value-of select="concat(']',normalize-space(substring-after($json-in,']')))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(',',normalize-space(substring-after($json-in,',')))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<so:output>
<xsl:element name="{$parent-ele}">
<xsl:value-of select="$value" />
</xsl:element>
</so:output>
<xsl:if test="$remainder">
<so:extra><xsl:value-of select="$remainder" /></so:extra>
</xsl:if>
</xsl:template>
<xsl:template name="boolean">
<!-- Input like: "X" bla -->
<!-- output like: <so:output><Y>X</Y></so:output> <so:extra>bla</so:extra> -->
<xsl:param name="json-in" />
<xsl:param name="parent-ele" />
<xsl:variable name="value">
<xsl:choose>
<xsl:when test="contains(substring-before($json-in,','),'}')">
<xsl:value-of select="normalize-space(substring-before($json-in,'}'))"/>
</xsl:when>
<xsl:when test="contains(substring-before($json-in,','),']')">
<xsl:value-of select="normalize-space(substring-before($json-in,']'))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="normalize-space(substring-before($json-in,','))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="remainder">
<xsl:choose>
<xsl:when test="contains(substring-before($json-in,','),'}')">
<xsl:value-of select="concat('}',normalize-space(substring-after($json-in,'}')))"/>
</xsl:when>
<xsl:when test="contains(substring-before($json-in,','),']')">
<xsl:value-of select="concat(']',normalize-space(substring-after($json-in,']')))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(',',normalize-space(substring-after($json-in,',')))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<so:output>
<xsl:element name="{$parent-ele}">
<xsl:value-of select="$value" />
</xsl:element>
</so:output>
<xsl:if test="$remainder">
<so:extra><xsl:value-of select="$remainder" /></so:extra>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
The question is tagged for XSLT 1.0, so I do not know if this answer will help the original question. But if you can use XSLT 3.0, the function json-to-xml does exactly what you need.
https://www.w3.org/TR/xslt-30/#func-json-to-xml
As well as Dimitre's XSLT parsing framework, there is also Gunther Rademacher's Rex parser generator, which also includes JSON as one of its sample grammars:
http://www.bottlecaps.de/rex/
Try this lib:
https://github.com/bramstein/xsltjson
Looks very nice.
Its a 2.0 XSLT solution, although he also points to 1.0 version.
XSLT has many strengths and a few big weaknesses. Text processing is its weakness at least version 1.0
Although it would be technically possible to process that text with XSLT 1.0, I can't think of any situation where it would be a very good idea, and where it wouldn't be a very fragile conversion. The code you would have to produce would be very unwieldy.
Is there no other language available to you to do the processing?

I want to split the string stored in a variable and store the obtained values in variable using xslt

<xsl:variable name="AAM" select="//AAM"/>
AAM will have string value_1,value_2,value_3,value_4
I then want to split this and store in 4 variables :
seg1,
seg2,
seg3,
seg4
Assuming the below as your input:
<?xml version="1.0" encoding="UTF-8"?>
<body>
<AAM>value_1,value_2,value_3,value_4</AAM>
</body>
An XSLT 2.0 solution to split a comma separated string can be:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:variable name="AAM" select="//AAM" />
<xsl:template match="body">
<body>
<xsl:variable name="separator" select="','" />
<xsl:for-each select="tokenize($AAM,$separator)">
<xsl:element name="seg{position()}">
<xsl:value-of select="normalize-space(.)" />
</xsl:element>
</xsl:for-each>
</body>
</xsl:template>
http://xsltransform.net/6qaFCET/1
Edit: (Based on commented)
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:variable name="AAM" select="//AAM" />
<xsl:template match="body">
<body>
<xsl:variable name="separator" select="','" />
<xsl:for-each select="tokenize($AAM,$separator)">
<xsl:choose>
<xsl:when test="position() = 1">
<xsl:variable name="seg1">
<xsl:value-of select="normalize-space(.)" />
</xsl:variable>
<xsl:copy-of select="$seg1" />
<xsl:text>
</xsl:text>
</xsl:when>
<xsl:when test="position() = 2">
<xsl:variable name="seg2">
<xsl:value-of select="normalize-space(.)" />
</xsl:variable>
<xsl:copy-of select="$seg2" />
<xsl:text>
</xsl:text>
</xsl:when>
<xsl:when test="position() = 3">
<xsl:variable name="seg3">
<xsl:value-of select="normalize-space(.)" />
</xsl:variable>
<xsl:copy-of select="$seg3" />
<xsl:text>
</xsl:text>
</xsl:when>
<xsl:when test="position() = 4">
<xsl:variable name="seg4">
<xsl:value-of select="normalize-space(.)" />
</xsl:variable>
<xsl:copy-of select="$seg4" />
<xsl:text>
</xsl:text>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</body>
</xsl:template>
http://xsltransform.net/6qaFCET/2
Note: following lines can be avoided. It has been added to populate value of variables.
<xsl:copy-of select="$seg2" />
<xsl:text>
</xsl:text>
Assuming you have <AAM>value_1,value_2,value_3,value_4</AAM> and <xsl:variable name="AAM" select="//AAM"/> you can of course use e.g. <xsl:variable name="value-sequence" select="tokenize($AAM, ',')"/> and if then needed access e.g. $value-sequence[1], $value-sequence[2] and so on, thus if you know there are only four values you can declare <xsl:variable name="seq1" select="$value-sequence[1]"/>, <xsl:variable name="seq2" select="$value-sequence[2]"/> and so on. The tokenize function is part of XPath 2 and later so works with XSLT 2 or 3 processors like Saxon 9 or AltovaXML or XmlPrime.
Answering late.
Maybe this is not an exact solution. But this may help you.
This is how I'm able to split a string from an XML node into two variables using XSLT 1.0
<xsl:when test="NodeName">
<xsl:variable name="var" select="NodeName"/>
<xsl:variable name="var1" select="substring-before($var, '=')"/>
<xsl:variable name="var2" select="substring-after($var, '=')"/>
<xsl:value-of select="$var1"/>-
<xsl:value-of select="$var2"/>
</xsl:when>
For Further reference Click Here

Otherwise XSLT1.0 - correct output

I´ve a problem at my xslt.
Here it is:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="GRP">
<xsl:copy>
<!--copy the data from ADD - ST to the GRP so it can be used in the mapping to set the delivery address from end customer-->
<xsl:for-each select ="./ADD">
<xsl:if test="./QUALIFIER='ST'">
<xsl:copy-of select="PARTY_NAME_1"/>
<xsl:copy-of select="STREET_1"/>
<xsl:copy-of select="CITY"/>
<xsl:copy-of select="POSTAL_CODE"/>
<xsl:copy-of select="COUNTRY_CODE"/>
</xsl:if>
<xsl:choose>
<xsl:when test="./QUALIFIER='CN'">
<CONTACT_NUMBER>
<xsl:value-of select="CONTACT/NUMBER"/>
</CONTACT_NUMBER>
</xsl:when>
<xsl:otherwise>
<xsl:if test="./QUALIFIER='ST'">
<CONTACT_NUMBER>
<xsl:value-of select="CONTACT/NUMBER"/>
</CONTACT_NUMBER>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<!--copy all other nodes-->
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Can you tell me, whats my mistake at my xml?
At my code i get Contact_Number 2 times.
I just like one of them... If Contact at CN - use this, otherwise use from ST.
-> If contact at CN and ST use CN.
Edit: xml:
<SEEDELFOR>
<GRP>
<ADD>
<QUALIFIER>CN</QUALIFIER>
<IDENTIFIER></IDENTIFIER>
<AGENCY_CODE></AGENCY_CODE>
<PARTY_NAME_1></PARTY_NAME_1>
<STREET_1></STREET_1>
<CITY></CITY>
<POSTAL_CODE></POSTAL_CODE>
<COUNTRY_CODE></COUNTRY_CODE>
<CONTACT>
<QUALIFIER></QUALIFIER>
<NUMBER>1111111</NUMBER>
</CONTACT>
</ADD>
<ADD>
<QUALIFIER>ST</QUALIFIER>
<IDENTIFIER></IDENTIFIER>
<AGENCY_CODE></AGENCY_CODE>
<PARTY_NAME_1></PARTY_NAME_1>
<STREET_1></STREET_1>
<CITY></CITY>
<POSTAL_CODE></POSTAL_CODE>
<CONTACT>
<QUALIFIER></QUALIFIER>
<NUMBER>2222222</NUMBER>
</CONTACT>
</ADD>
</GRP>
</SEEDELFOR>
How can i correct my xslt?
I hope you can help me.
Best regards
Julian
One of the way you can achieve this is, rewriting the template GRP as following:
<xsl:template match="GRP">
<xsl:copy>
<!--copy the data from ADD - ST to the GRP so it can be used in the mapping
to set the delivery address from end customer -->
<xsl:variable name="contact_ST">
<xsl:for-each select="./ADD">
<xsl:if test="./QUALIFIER='ST'">
<CONTACT_NUMBER>
<xsl:value-of select="CONTACT/NUMBER" />
</CONTACT_NUMBER>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="contact_CN">
<xsl:for-each select="./ADD">
<xsl:if test="./QUALIFIER='CN'">
<CONTACT_NUMBER>
<xsl:value-of select="CONTACT/NUMBER" />
</CONTACT_NUMBER>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="./ADD">
<xsl:if test="./QUALIFIER='ST'">
<xsl:copy-of select="PARTY_NAME_1" />
<xsl:copy-of select="STREET_1" />
<xsl:copy-of select="CITY" />
<xsl:copy-of select="POSTAL_CODE" />
<xsl:copy-of select="COUNTRY_CODE" />
</xsl:if>
</xsl:for-each>
<xsl:choose>
<xsl:when test="$contact_CN != ''">
<xsl:copy-of select="$contact_CN" />
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$contact_ST" />
</xsl:otherwise>
</xsl:choose>
<!--copy all other nodes -->
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
Consider the following simplified example:
<xsl:template match="GRP">
<xsl:copy>
<!-- other code, if necessary-->
<xsl:variable name="cn" select="ADD[QUALIFIER='CN']" />
<xsl:variable name="st" select="ADD[QUALIFIER='ST']" />
<CONTACT_NUMBER>
<xsl:choose>
<xsl:when test="$cn">
<xsl:value-of select="$cn/CONTACT/NUMBER"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$st/CONTACT/NUMBER"/>
</xsl:otherwise>
</xsl:choose>
</CONTACT_NUMBER>
<!-- more code, if necessary-->
</xsl:copy>
</xsl:template>

XSL Replace an element by splitting it's values

I have the following XML which contains the order details in single element.
<?xml version="1.0" encoding="UTF-8"?>
<MESSAGE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MESSAGE_ID>361155</MESSAGE_ID>
<NAME>Header123</NAME>
<HEADERS>
<HEADER>
<ACTION_COUNT>1</ACTION_COUNT>
<ACTION_DESC>
<DAILY_LOAD>
<LOAD_NO>1</LOAD_NO>
<CUSTOMER_NO>09656951</CUSTOMER_NO>
<REFERENCE xsi:nil="1"/>
<SERIAL>450255470000403803</SERIAL>
<ORDERS>
<ORDER>
<ITEM>5000128762885</ITEM>
<DETAILS>4582;Robert and Co;8;5526;SWD</DETAILS>
<EMP_NO>13</EMP_NO>
<USE_BY_DATE>20110611</USE_BY_DATE>
<DEPOT>5000128910035</DEPOT>
</ORDER>
<ORDER>
<ITEM>5000128853613</ITEM>
<DETAILS>5000;Anne and Co;9;2020;ATM</DETAILS>
<EMP_NO>5</EMP_NO>
<USE_BY_DATE>20110613</USE_BY_DATE>
<DEPOT>5000128910035</DEPOT>
</ORDER>
</ORDERS>
</DAILY_LOAD>
</ACTION_DESC>
</HEADER>
</HEADERS>
<LIST_ID>23689</LIST_ID>
<TRAILER>TEST_NEEDED</TRAILER>
</MESSAGE>
I need that to be transformed into the following format.
(only the DAILY_LOAD>ORDERS section should be changed as below)
.....
<ORDERS>
<ORDER>
<ITEM>5000128762885</ITEM>
<ORDER_NO>4582</ORDER_NO>
<CUSTOMER>Robert and Co</CUSTOMER>
<NO_OF_ITEMS>8</NO_OF_ITEMS>
<TOTAL>5526</TOTAL>
<LOCATION>SWD</LOCATION>
<EMP_NO>13</EMP_NO>
<USE_BY_DATE>20110611</USE_BY_DATE>
<DEPOT>5000128910035</DEPOT>
</ORDER>
<ORDER>
<ITEM>5000128853613</ITEM>
<ORDER_NO>5000</ORDER_NO>
<CUSTOMER>Anne and Co</CUSTOMER>
<NO_OF_ITEMS>9</NO_OF_ITEMS>
<TOTAL>2020</TOTAL>
<LOCATION>ATM</LOCATION>
<EMP_NO>5</EMP_NO>
<USE_BY_DATE>20110613</USE_BY_DATE>
<DEPOT>5000128910035</DEPOT>
</ORDER>
</ORDERS>
.....
The transformed XML contains no but it's divided into CUSTOMER, NO_OF_ITEMS, TOTAL and LOCATION. Any suggestion or help will be highly appreciated.
Thank you in advance.
XSLT 1.0
Using tokenizeString template as suggested in Heber.it blog. I have modified the code for producing different tag names depending on recursion level (ORDER_NO, CUSTOMER, NO_OF_ITEMS, etc).
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<!-- replaces order nodes -->
<xsl:template match="ORDER">
<ORDER>
<xsl:call-template name="tokenizeString">
<xsl:with-param name="list" select="./DETAILS"/>
<xsl:with-param name="delimiter" select="';'"/>
<xsl:with-param name="level" select="1"/>
</xsl:call-template>
</ORDER>
</xsl:template>
<!-- copy everything that doesn't match another template -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<!-- template to tokenize strings -->
<xsl:template name="tokenizeString">
<!--passed template parameter -->
<xsl:param name="list"/>
<xsl:param name="delimiter"/>
<xsl:param name="level"/>
<xsl:choose>
<xsl:when test="contains($list, $delimiter)">
<xsl:choose>
<xsl:when test="$level = 1">
<ITEM>
<xsl:value-of select="ITEM"/>
</ITEM>
<ORDER_NO>
<xsl:value-of select="substring-before($list,$delimiter)"/>
</ORDER_NO>
</xsl:when>
<xsl:when test="$level = 2">
<CUSTOMER>
<xsl:value-of select="substring-before($list,$delimiter)"/>
</CUSTOMER>
</xsl:when>
<xsl:when test="$level = 3">
<NO_OF_ITEMS>
<xsl:value-of select="substring-before($list,$delimiter)"/>
</NO_OF_ITEMS>
</xsl:when>
<xsl:when test="$level = 4">
<TOTAL>
<xsl:value-of select="substring-before($list,$delimiter)"/>
</TOTAL>
</xsl:when>
</xsl:choose>
<xsl:call-template name="tokenizeString">
<!-- store anything left in another variable -->
<xsl:with-param name="list" select="substring-after($list,$delimiter)"/>
<xsl:with-param name="delimiter" select="$delimiter"/>
<xsl:with-param name="level" select="$level + 1"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$list = ''">
<xsl:text/>
</xsl:when>
<xsl:otherwise>
<LOCATION>
<xsl:value-of select="$list"/>
</LOCATION>
<EMP_NO>
<xsl:value-of select="EMP_NO"/>
</EMP_NO>
<USE_BY_DATE>
<xsl:value-of select="USE_BY_DATE"/>
</USE_BY_DATE>
<DEPOT>
<xsl:value-of select="DEPOT"/>
</DEPOT>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
XSLT 2.0
Using tokenize function you can do this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<!-- this template replaces order nodes -->
<xsl:template match="ORDER">
<ORDER>
<xsl:variable name="fields" select="tokenize(DETAILS, ';')"/>
<ITEM>
<xsl:value-of select="ITEM"/>
</ITEM>
<ORDER_NO>
<xsl:value-of select="$fields[position()=1]"/>
</ORDER_NO>
<CUSTOMER>
<xsl:value-of select="$fields[position()=2]"/>
</CUSTOMER>
<NO_OF_ITEMS>
<xsl:value-of select="$fields[position()=3]"/>
</NO_OF_ITEMS>
<TOTAL>
<xsl:value-of select="$fields[position()=4]"/>
</TOTAL>
<LOCATION>
<xsl:value-of select="$fields[position()=5]"/>
</LOCATION>
<EMP_NO>
<xsl:value-of select="EMP_NO"/>
</EMP_NO>
<USE_BY_DATE>
<xsl:value-of select="USE_BY_DATE"/>
</USE_BY_DATE>
<DEPOT>
<xsl:value-of select="DEPOT"/>
</DEPOT>
</ORDER>
</xsl:template>
<!-- this template copies everything that doesn't match another template -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Reading values of XML tag in variables inside XSLT

I could not find a similar question anywhere, so thats why posting this new question.
I have an XML that I want to read and convert into SQL using XSLT. The trick part is that the XML elements(i.e. the names) are not known and the XSD for the XML is generated on the fly.
But what is known is certain attributes of the elements.
The XML looks like this :
<?xml version="1.0" encoding="UTF-8"?>
<et:ItemRecordList xmlns:et="urn:org:easetech:easytest:schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:org:easetech:easytest:schema ItemRecord.xsd ">
<ItemRecord recordId="idvalue0" tableName="item_record">
<itemId columnName="item_id" idColumn="true" length="36" nullable="false">itemId</itemId>
<databaseInstitution columnName="database_institution" length="255" nullable="false">0</databaseInstitution>
<lastModifiedDate columnName="last_modified_date" length="255" nullable="false">2001-12-31T12:00:00</lastModifiedDate>
</ItemRecord>
</et:ItemRecordList>
I want to use this XML and convert it into an INSERT SQL statement using XXSLT.
I created an XSLT like this :
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="/">
<xsl:for-each select="/*/*">
INSERT INTO
<xsl:value-of select="#tableName" />
(
<xsl:for-each select="/*/*/*">
<xsl:variable name="columnName"><xsl:value-of select="#columnName"/></xsl:variable>
<xsl:choose>
<xsl:when test="#columnName">
<xsl:value-of select="$columnName"/>
<xsl:if test="position()!=last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:when>
</xsl:choose>
</xsl:for-each>
)
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
which gives me the output like this :
INSERT INTO item_record (item_id, database_institution, last_modified_date)
But I don't know how to create the value part of the query. The value is the value we get using
<xsl:value-of select="." />
I tried concatenating the values, but unfortunately concat didnt work for me. I also played around with xsl:variable but couldnt make it work. If someone could help me with the XSLT that I can use to create to output like below that would be really appreciated.
INSERT INTO item_record (item_id, database_institution, last_modified_date) values (itemId,0,2001-12-31T12:00:00)
How about:
<xsl:template match="/">
<xsl:for-each select="/*/*">
<xsl:text>INSERT INTO </xsl:text>
<xsl:value-of select="#tableName" />
<xsl:text> (</xsl:text>
<xsl:for-each select="*[#columnName]">
<xsl:value-of select="#columnName"/>
<xsl:if test="position()!=last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>) values (</xsl:text>
<xsl:for-each select="*[#columnName]">
<xsl:value-of select="."/>
<xsl:if test="position()!=last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
The next XSLT will generate the query as wanted
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:variable name="newline" select="'
'" />
<xsl:template match="/">
<xsl:apply-templates select="*/*/#tableName" />
</xsl:template>
<xsl:template match="#tableName">
<xsl:value-of select="concat('INSERT INTO ', ., ' (')" />
<xsl:apply-templates select="parent::*/*/#columnName" />
<xsl:value-of select="') VALUES ('" />
<xsl:apply-templates select="parent::*/*" mode="values" />
<xsl:value-of select="concat(')', $newline)" />
</xsl:template>
<xsl:template match="#columnName">
<xsl:choose>
<xsl:when test="position() = last()">
<xsl:value-of select="." />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(., ', ')" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*" mode="values">
<xsl:choose>
<xsl:when test="position() = last()">
<xsl:value-of select="." />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(., ', ')" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>