Template Name and call-template - xslt-1.0

i have xslt for change status transaction. i can change for template who was in scope at template name bodys. but the plan was when data on headers have failed some condition and the status for the template bodys in node TxRsnSts need change too. but i cant get the value from headers. how i can get the value from headers and submit on variable name TxRsnStsB.
This the XSLT script i make
<xsl:stylesheet version="1.0" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:ns1="urn:iso:std:iso:20022:tech:xsd:head.001.001.01" xmlns:ns2="urn:iso:std:iso:20022:tech:xsd:pacs.002.001.10" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="no" method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/">
<ns:BusMsg xmlns:ns="urn:iso" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso ../../../xsd/phase1/MainCIHub.xsd">
<ns1:AppHdr>
<xsl:call-template name="headers">
<xsl:with-param name="CpyDplct" select="//BusMsg/AppHdr/CpyDplct"/>
<xsl:with-param name="PssblDplct" select="//BusMsg/AppHdr/PssblDplct"/>
<xsl:with-param name="Sgntr" select="//BusMsg/AppHdr/Sgntr"/>
</xsl:call-template>
</ns1:AppHdr>
<ns:Document>
<ns:FIToFIPmtStsRpt>
<xsl:call-template name="bodys">
<xsl:with-param name="CtgyPurpB" select="//BusMsg/Document/FItoFICstmrCdtTrf/CdtTrfTxInf/PmtTpInf/CtgyPurp/Prtry"/>
<xsl:with-param name="IntrBkSttlmAmtB" select="//BusMsg/Document/FItoFICstmrCdtTrf/CdtTrfTxInf/IntrBkSttlmAmt/Value"/>
<xsl:with-param name="CcyB" select="//BusMsg/Document/FItoFICstmrCdtTrf/CdtTrfTxInf/IntrBkSttlmAmt/Ccy"/>
</xsl:call-template>
</ns:FIToFIPmtStsRpt>
</ns:Document>
</ns:BusMsg>
</xsl:template>
<xsl:template name="headers">
<xsl:param name="CpyDplct"/>
<xsl:param name="PssblDplct"/>
<xsl:param name="Sgntr"/>
<xsl:variable name="flagCpyDplcts">
<xsl:choose>
<xsl:when test="$CpyDplct = ''"/>
<xsl:when test="string-length($CpyDplct) <= 35 and ($CpyDplct = 'CODU' or $CpyDplct = 'COPY' or $CpyDplct = 'DUPL')">
<xsl:value-of select="$CpyDplct"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:copy-of select="$CpyDplct"/>
</xsl:copy>
<xsl:value-of select="'U0002'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="flagPssblDplcts">
<xsl:choose>
<xsl:when test="$PssblDplct = ''"/>
<xsl:when test="string-length($PssblDplct) <= 35 and ($PssblDplct = 'true' or $PssblDplct = 'false')">
<xsl:value-of select="$PssblDplct"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:copy-of select="$PssblDplct"/>
</xsl:copy>
<xsl:value-of select="'U0002'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="flagSgntrs">
<xsl:choose>
<xsl:when test="$Sgntr = ''"/>
<xsl:when test="string-length($Sgntr) <= 35">
<xsl:value-of select="$Sgntr"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:copy-of select="$PssblDplct"/>
</xsl:copy>
<xsl:value-of select="'U0012'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<ns1:CpyDplct>
<xsl:value-of select="$flagCpyDplcts"/>
</ns1:CpyDplct>
<ns1:PssblDplct>
<xsl:value-of select="$flagPssblDplcts"/>
</ns1:PssblDplct>
<ns1:Sgntr>
<xsl:value-of select="$flagSgntrs"/>
</ns1:Sgntr>
</xsl:template>
<xsl:template name="bodys">
<xsl:param name="CtgyPurpB"/>
<xsl:param name="IntrBkSttlmAmtB"/>
<xsl:param name="CcyB"/>
<xsl:variable name="flagCtgyPurpBs">
<xsl:variable name="payT" select="substring($CtgyPurpB,1,3)"/>
<xsl:variable name="catP" select="substring($CtgyPurpB,4,2)"/>
<xsl:choose>
<xsl:when test="not(contains($payT,'010') or contains($payT,'011') or contains($payT,'019') or contains($payT,'110') or contains($payT,'510') or contains($payT,'610') or contains($payT,'710') or contains($payT,'720') or contains($payT,'000'))">
<xsl:value-of select="'U0002'"/>
</xsl:when>
<xsl:when test="not(contains($catP,'01') or contains($catP,'02') or contains($catP,'03') or contains($catP,'99'))">
<xsl:value-of select="'U0002'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$CtgyPurpB"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="flagIntrBkSttlmAmtBs">
<xsl:variable name="amount" select="substring-before($IntrBkSttlmAmtB,'.')"/>
<xsl:variable name="decimal" select="substring-after($IntrBkSttlmAmtB,'.')"/>
<xsl:choose>
<xsl:when test="not(fn:matches($IntrBkSttlmAmtB, '^[0-9.]*$'))">
<xsl:value-of select="'U0038'"/>
</xsl:when>
<xsl:when test="not(string-length($amount) <= 16)">
<xsl:value-of select="'U0038'"/>
</xsl:when>
<xsl:when test="not(string-length($decimal) <= 2)">
<xsl:value-of select="'U0038'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$IntrBkSttlmAmtB"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="flagCcyBs">
<xsl:choose>
<xsl:when test="not(fn:matches($CcyB, '^[a-zA-Z0-9]*$') and string-length($CcyB) <= 3)">
<xsl:value-of select="'U0038'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$CcyB"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<ns1:CtgyPurp>
<xsl:value-of select="$flagCtgyPurpBs"/>
</ns1:CtgyPurp>
<ns1:IntrBkSttlmAmt>
<xsl:value-of select="$flagIntrBkSttlmAmtBs"/>
</ns1:IntrBkSttlmAmt>
<ns1:Ccy>
<xsl:value-of select="$flagCcyBs"/>
</ns1:Ccy>
<xsl:variable name="TxRsnStsB">
<xsl:choose>
<xsl:when
test="contains($flagSgntrs, 'U0012') or contains($flagSgntrs, 'U0002') or contains($flagSgntrs, 'U0038') or contains($flagPssblDplcts, 'U0012') or contains($flagPssblDplcts, 'U0002') or contains($flagPssblDplcts, 'U0038') or contains($flagCpyDplcts, 'U0012') or contains($flagCpyDplcts, 'U0002') or contains($flagCpyDplcts, 'U0038') or contains($flagCtgyPurpBs, 'U0012') or contains($flagCtgyPurpBs, 'U0002') or contains($flagCtgyPurpBs, 'U0038') or contains($flagIntrBkSttlmAmtBs, 'U0012') or contains($flagIntrBkSttlmAmtBs, 'U0002') or contains($flagIntrBkSttlmAmtBs, 'U0038') or contains($flagCcyBs, 'U0012') or contains($flagCcyBs, 'U0002') or contains($flagCcyBs, 'U0038')">
<xsl:value-of select="'Decline'" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'Approve'" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<ns1:TxRsnSts><xsl:value-of select="$TxRsnStsB"/></ns1:TxRsnSts>
</xsl:template>
</xsl:stylesheet>

Your question is hard to understand.
If you want to reuse the variabels you have declared in headers inside body, you have two options:
Save the result of headers inside a variable and use that as a parameter in your call to bodys.
The other option is to declare those variables as globals like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:ns1="urn:iso:std:iso:20022:tech:xsd:head.001.001.01"
xmlns:ns2="urn:iso:std:iso:20022:tech:xsd:pacs.002.001.10"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="no" method="xml" omit-xml-declaration="yes"/>
<xsl:variable name="CpyDplct" select="//BusMsg/AppHdr/CpyDplct"/>
<xsl:variable name="PssblDplct" select="//BusMsg/AppHdr/PssblDplct"/>
<xsl:variable name="Sgntr" select="//BusMsg/AppHdr/Sgntr"/>
<xsl:variable name="flagCpyDplcts">
<xsl:choose>
<xsl:when test="$CpyDplct = ''"/>
<xsl:when test="string-length($CpyDplct) <= 35 and ($CpyDplct = 'CODU' or $CpyDplct = 'COPY' or $CpyDplct = 'DUPL')">
<xsl:value-of select="$CpyDplct"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:copy-of select="$CpyDplct"/>
</xsl:copy>
<xsl:value-of select="'U0002'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="flagPssblDplcts">
<xsl:choose>
<xsl:when test="$PssblDplct = ''"/>
<xsl:when test="string-length($PssblDplct) <= 35 and ($PssblDplct = 'true' or $PssblDplct = 'false')">
<xsl:value-of select="$PssblDplct"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:copy-of select="$PssblDplct"/>
</xsl:copy>
<xsl:value-of select="'U0002'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="flagSgntrs">
<xsl:choose>
<xsl:when test="$Sgntr = ''"/>
<xsl:when test="string-length($Sgntr) <= 35">
<xsl:value-of select="$Sgntr"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:copy-of select="$PssblDplct"/>
</xsl:copy>
<xsl:value-of select="'U0012'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:template match="/">
<ns:BusMsg xmlns:ns="urn:iso" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso ../../../xsd/phase1/MainCIHub.xsd">
<ns1:AppHdr>
<xsl:call-template name="headers"/>
</ns1:AppHdr>
<ns:Document>
<ns:FIToFIPmtStsRpt>
<xsl:call-template name="bodys">
<xsl:with-param name="CtgyPurpB" select="//BusMsg/Document/FItoFICstmrCdtTrf/CdtTrfTxInf/PmtTpInf/CtgyPurp/Prtry"/>
<xsl:with-param name="IntrBkSttlmAmtB" select="//BusMsg/Document/FItoFICstmrCdtTrf/CdtTrfTxInf/IntrBkSttlmAmt/Value"/>
<xsl:with-param name="CcyB" select="//BusMsg/Document/FItoFICstmrCdtTrf/CdtTrfTxInf/IntrBkSttlmAmt/Ccy"/>
</xsl:call-template>
</ns:FIToFIPmtStsRpt>
</ns:Document>
</ns:BusMsg>
</xsl:template>
<xsl:template name="headers">
<ns1:CpyDplct>
<xsl:value-of select="$flagCpyDplcts"/>
</ns1:CpyDplct>
<ns1:PssblDplct>
<xsl:value-of select="$flagPssblDplcts"/>
</ns1:PssblDplct>
<ns1:Sgntr>
<xsl:value-of select="$flagSgntrs"/>
</ns1:Sgntr>
</xsl:template>
<xsl:template name="bodys">
<xsl:param name="CtgyPurpB"/>
<xsl:param name="IntrBkSttlmAmtB"/>
<xsl:param name="CcyB"/>
<xsl:param name="header"/>
<xsl:variable name="flagCtgyPurpBs">
<xsl:variable name="payT" select="substring($CtgyPurpB,1,3)"/>
<xsl:variable name="catP" select="substring($CtgyPurpB,4,2)"/>
<xsl:choose>
<xsl:when test="not(contains($payT,'010') or contains($payT,'011') or contains($payT,'019') or contains($payT,'110') or contains($payT,'510') or contains($payT,'610') or contains($payT,'710') or contains($payT,'720') or contains($payT,'000'))">
<xsl:value-of select="'U0002'"/>
</xsl:when>
<xsl:when test="not(contains($catP,'01') or contains($catP,'02') or contains($catP,'03') or contains($catP,'99'))">
<xsl:value-of select="'U0002'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$CtgyPurpB"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="flagIntrBkSttlmAmtBs">
<xsl:variable name="amount" select="substring-before($IntrBkSttlmAmtB,'.')"/>
<xsl:variable name="decimal" select="substring-after($IntrBkSttlmAmtB,'.')"/>
<xsl:choose>
<xsl:when test="not(fn:matches($IntrBkSttlmAmtB, '^[0-9.]*$'))">
<xsl:value-of select="'U0038'"/>
</xsl:when>
<xsl:when test="not(string-length($amount) <= 16)">
<xsl:value-of select="'U0038'"/>
</xsl:when>
<xsl:when test="not(string-length($decimal) <= 2)">
<xsl:value-of select="'U0038'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$IntrBkSttlmAmtB"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="flagCcyBs">
<xsl:choose>
<xsl:when test="not(fn:matches($CcyB, '^[a-zA-Z0-9]*$') and string-length($CcyB) <= 3)">
<xsl:value-of select="'U0038'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$CcyB"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<ns1:CtgyPurp>
<xsl:value-of select="$flagCtgyPurpBs"/>
</ns1:CtgyPurp>
<ns1:IntrBkSttlmAmt>
<xsl:value-of select="$flagIntrBkSttlmAmtBs"/>
</ns1:IntrBkSttlmAmt>
<ns1:Ccy>
<xsl:value-of select="$flagCcyBs"/>
</ns1:Ccy>
<xsl:variable name="TxRsnStsB">
<xsl:choose>
<xsl:when test="contains($flagSgntrs, 'U0012') or contains($flagSgntrs, 'U0002') or contains($flagSgntrs, 'U0038') or contains($flagPssblDplcts, 'U0012') or contains($flagPssblDplcts, 'U0002') or contains($flagPssblDplcts, 'U0038') or contains($flagCpyDplcts, 'U0012') or contains($flagCpyDplcts, 'U0002') or contains($flagCpyDplcts, 'U0038') or contains($flagCtgyPurpBs, 'U0012') or contains($flagCtgyPurpBs, 'U0002') or contains($flagCtgyPurpBs, 'U0038') or contains($flagIntrBkSttlmAmtBs, 'U0012') or contains($flagIntrBkSttlmAmtBs, 'U0002') or contains($flagIntrBkSttlmAmtBs, 'U0038') or contains($flagCcyBs, 'U0012') or contains($flagCcyBs, 'U0002') or contains($flagCcyBs, 'U0038')">
<xsl:value-of select="'Decline'" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'Approve'" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<ns1:TxRsnSts><xsl:value-of select="$TxRsnStsB"/></ns1:TxRsnSts>
</xsl:template>
</xsl:stylesheet>

Related

XSLT 1.0 Conditional Value

i have conditional like this:
<xsl:variable name="MsgIdBs">
<xsl:variable name="dateB" select="substring($MsgIdB,1,8)"/>
<xsl:variable name="biCodeB" select="substring($MsgIdB,9,8)"/>
<xsl:variable name="trTpB" select="substring($MsgIdB,17,3)"/>
<xsl:variable name="snB" select="substring($MsgIdB,20,8)"/>
<xsl:choose>
<xsl:when test="not(fn:matches($MsgIdB, '^[a-zA-Z0-9]*$') and string-length($MsgIdB) <= 35)">
<xsl:copy>
<xsl:copy-of select="$MsgIdB"/>
</xsl:copy>
<xsl:variable name="flag" select="'false'"/>
</xsl:when>
<xsl:when test="not(number(substring($dateB, 1, 4)) >= 1970 and number(substring($dateB, 5, 2)) <= 12 and number(substring($dateB, 7, 2)) <= 31)">
<xsl:copy>
<xsl:copy-of select="$MsgIdB"/>
</xsl:copy>
<xsl:variable name="flag" select="'false'"/>
</xsl:when>
<xsl:when test="not(contains($trTpB,'010') or contains($trTpB,'011') or contains($trTpB,'019') or contains($trTpB,'110') or contains($trTpB,'510') or contains($trTpB,'610') or contains($trTpB,'710') or contains($trTpB,'720') or contains($trTpB,'000'))">
<xsl:copy>
<xsl:copy-of select="$MsgIdB"/>
</xsl:copy>
<xsl:variable name="flag" select="'false'"/>
</xsl:when>
<xsl:when test="not(fn:matches($snB, '^\d+$'))">
<xsl:copy>
<xsl:copy-of select="$MsgIdB"/>
</xsl:copy>
<xsl:variable name="flag" select="'false'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$MsgIdB"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
and i have a variable to check value from variable name flag. but i always get value from otherwise. never get value from variable flag on conditional. the code like this:
<xsl:variable name="output">
<xsl:choose>
<xsl:when test="$flag = 'false'">
<ns2:TxSts>Not Deal</ns2:TxSts>
</xsl:when>
<xsl:otherwise>
<ns2:TxSts>Deal</ns2:TxSts>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
how i can get the value from variable name flag on conditional and compare base with variable output.
Create a seperate variable for flag. This will keep the flag varible in scope for use in following code.
<xsl:variable name="flag">
<xsl:variable name="dateB" select="substring($MsgIdB,1,8)"/>
<xsl:variable name="biCodeB" select="substring($MsgIdB,9,8)"/>
<xsl:variable name="trTpB" select="substring($MsgIdB,17,3)"/>
<xsl:variable name="snB" select="substring($MsgIdB,20,8)"/>
<xsl:choose>
<xsl:when test="not(number(substring($dateB, 1, 4)) >= 1970 and number(substring($dateB, 5, 2)) <= 12 and number(substring($dateB, 7, 2)) <= 31)">
<xsl:value-of select="'false'"/>
</xsl:when>
<xsl:when test="not(contains($trTpB,'010') or contains($trTpB,'011') or contains($trTpB,'019') or contains($trTpB,'110') or contains($trTpB,'510') or contains($trTpB,'610') or contains($trTpB,'710') or contains($trTpB,'720') or contains($trTpB,'000'))">
<xsl:value-of select="'false'"/>
</xsl:when>
<xsl:when test="not(fn:matches($snB, '^\d+$'))">
<xsl:value-of select="'false'"/>
</xsl:when>
</xsl:choose>
</xsl:variable>
Use the flag to create MsgIdBs.
<xsl:variable name="MsgIdBs">
<xsl:choose>
<xsl:when test="contains($flag, 'false)">
<xsl:copy>
<xsl:copy-of select="$MsgIdB"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$MsgIdB"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
Use the flag again to create output.
<xsl:variable name="output">
<xsl:choose>
<xsl:when test="contains($flag, 'false)">
<ns2:TxSts>Not Deal</ns2:TxSts>
</xsl:when>
<xsl:otherwise>
<ns2:TxSts>Deal</ns2:TxSts>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>

I need to start the delem (concept-expected output) after r4 (conbody- expected output), which is not happening

I need to start the delem (concept-expected output) after r4 (conbody- expected output), currently with respect to r4 mapping, conbody is wrapping the concept (delem).
Basically, I want r4 conbody to end before delem (concept) element.
I am stuck, Need help with the solution.
Input xml
<?xml version="1.0" encoding="UTF-8"?>
<specif>
<rtit>Test specif</rtit>
<r3>
<rtit>Test r3</rtit>
<r4>
<rtit>Test r4</rtit>
<p> para Test r4</p>
<delem>
<p>para Test delem</p>
</delem>
<r6>
<rtit>Test r6</rtit>
<p>para Test r6</p>
</r6>
</r4>
</r3>
</specif>
current output
<?xml version="1.0" encoding="UTF-8"?>
<concept>
<title>Test specif</title>
<conbody/>
<concept>
<title>Test r3</title>
<conbody/>
<concept>
<title>Test r4</title>
<conbody>
<p> para Test r4</p>
<concept>
<title></title>
<conbody> <p> para Test delem</p> </conbody>
</concept>
</conbody>
<concept>
<title>Test r6</title>
<conbody> <p> para Test r6</p> </conbody>
</concept>
</concept>
</concept>
</concept>
Expected output
<?xml version="1.0" encoding="UTF-8"?>
<concept>
<title>Test specif</title>
<conbody/>
<concept>
<title>Test r3</title>
<conbody/>
<concept>
<title>Test r4</title>
<conbody><p> para Test r4</p></conbody>
<concept>
<title></title>
<conbody> <p> para Test delem</p> </conbody>
</concept>
<concept>
<title>Test r6</title>
<conbody> <p> para Test r6</p> </conbody>
</concept>
</concept>
</concept>
</concept>
XSL
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="sb/body/specif"/>
</xsl:template>
<xsl:template match="specif">
<concept>
<xsl:attribute name="xsi:noNamespaceSchemaLocation" select="'techinfo.xsd'"/>
<xsl:choose>
<xsl:when test="not(#id)">
<xsl:attribute name="id">
<xsl:value-of select="'concept'"/>
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="(#id ='')">
<xsl:attribute name="id">
<xsl:value-of select="'concept'"/>
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="(#id !='')">
<xsl:attribute name="id">
<xsl:value-of select="#id"/>
</xsl:attribute>
</xsl:when>
</xsl:choose>
<xsl:attribute name="xml:lang">
<xsl:value-of select="'en'"/>
</xsl:attribute>
<xsl:apply-templates select="*[matches(local-name(),'r3')]"/>
</concept>
</xsl:template>
<xsl:template match="*[matches(local-name(),'r3')]">
<concept>
<xsl:choose>
<xsl:when test="not(#id)">
<xsl:attribute name="id">
<xsl:value-of select="'concept'"/>
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="(#id ='')">
<xsl:attribute name="id">
<xsl:value-of select="'concept'"/>
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="(#id !='')">
<xsl:attribute name="id">
<xsl:value-of select="#id"/>
</xsl:attribute>
</xsl:when>
</xsl:choose>
<xsl:attribute name="xml:lang">
<xsl:value-of select="'en'"/>
</xsl:attribute>
<title>
<xsl:for-each select="child::rtit">
<xsl:attribute name="id">
<xsl:value-of select="#id"/>
</xsl:attribute>
<xsl:apply-templates select="node()|#*|text()"/>
</xsl:for-each>
</title>
<conbody>
<xsl:apply-templates select="*[not(starts-with(local-name(),'r'))]"/>
</conbody>
<!-- apply recursive -->
<xsl:apply-templates select="*[matches(local-name(),'r4')]"/>
</concept>
</xsl:template>
<xsl:template match="*[matches(local-name(),'r4')]">
<concept>
<xsl:choose>
<xsl:when test="not(#id)">
<xsl:attribute name="id">
<xsl:value-of select="'concept'"/>
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="(#id ='')">
<xsl:attribute name="id">
<xsl:value-of select="'concept'"/>
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="(#id !='')">
<xsl:attribute name="id">
<xsl:value-of select="#id"/>
</xsl:attribute>
</xsl:when>
</xsl:choose>
<xsl:attribute name="xml:lang">
<xsl:value-of select="'en'"/>
</xsl:attribute>
<title>
<xsl:for-each select="child::rtit">
<xsl:attribute name="id">
<xsl:value-of select="#id"/>
</xsl:attribute>
<xsl:apply-templates select="node()|#*|text()"/>
</xsl:for-each>
</title>
<conbody>
<xsl:choose>
<xsl:when test="child::r5|r6|r7|r8|r9">
<xsl:apply-templates select="*[not(starts-with(local-name(),'r'))]"/>
</xsl:when>
<xsl:when test="child::delem">
<xsl:apply-templates select="*[not(starts-with(local-name(),'delem'))]"/>
</xsl:when>
</xsl:choose>
</conbody>
<!-- apply recursive -->
<xsl:choose>
<xsl:when test="child::r5|r6|r7|r8|r9">
<xsl:apply-templates select="*[matches(local-name(),'r[5-9]')]"/>
</xsl:when>
<xsl:when test="child::delem">
<xsl:apply-templates select="delem"/>
</xsl:when>
</xsl:choose>
</concept>
</xsl:template>
<!--tch on all nodes like r1, r2,r4,r5,r6 etc-->
<xsl:template match="*[matches(local-name(),'r[5-9]')]">
<concept>
<xsl:choose>
<xsl:when test="not(#id)">
<xsl:attribute name="id">
<xsl:value-of select="'concept'"/>
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="(#id ='')">
<xsl:attribute name="id">
<xsl:value-of select="'concept'"/>
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="(#id !='')">
<xsl:attribute name="id">
<xsl:value-of select="#id"/>
</xsl:attribute>
</xsl:when>
</xsl:choose>
<xsl:attribute name="xml:lang">
<xsl:value-of select="'en'"/>
</xsl:attribute>
<title>
<xsl:for-each select="child::rtit">
<xsl:attribute name="id">
<xsl:value-of select="#id"/>
</xsl:attribute>
<xsl:apply-templates select="node()|#*|text()"/>
</xsl:for-each>
</title>
<conbody>
<xsl:choose>
<xsl:when test="*[matches(local-name(),'r[5-9]')]">
<xsl:apply-templates select="*[not(starts-with(local-name(),'r'))]"/>
</xsl:when>
<xsl:when test="*[matches(local-name(),'delem')]">
<xsl:apply-templates select="*[not(starts-with(local-name(),'delem'))]"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="*[not(starts-with(local-name(),'r'))]"/>
</xsl:otherwise>
</xsl:choose>
</conbody>
<!-- apply recursive -->
<xsl:choose>
<xsl:when test="*[matches(local-name(),'r[5-9]')]">
<xsl:apply-templates select="*[matches(local-name(),'r[5-9]')]"/>
</xsl:when>
<xsl:when test="*[matches(local-name(),'delem')]">
<xsl:apply-templates select="*[matches(local-name(),'delem')]"/>
</xsl:when>
</xsl:choose>
</concept>
</xsl:template>
<xsl:template match="delem">
<xsl:choose>
<xsl:when test="*[matches(local-name(),'r[3-9]')]">
<concept>
<xsl:choose>
<xsl:when test="not(#id)">
<xsl:attribute name="id">
<xsl:value-of select="'concept'"/>
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="(#id ='')">
<xsl:attribute name="id">
<xsl:value-of select="'concept'"/>
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="(#id !='')">
<xsl:attribute name="id">
<xsl:value-of select="#id"/>
</xsl:attribute>
</xsl:when>
</xsl:choose>
<xsl:attribute name="xml:lang">
<xsl:value-of select="'en'"/>
</xsl:attribute>
<title>
<xsl:for-each select="child::rtit">
<xsl:attribute name="id">
<xsl:value-of select="#id"/>
</xsl:attribute>
<xsl:apply-templates select="node()|#*|text()"/>
</xsl:for-each>
</title>
<xsl:for-each select="child::subtitle">
<shortdesc>
<xsl:attribute name="id">
<xsl:value-of select="#id"/>
</xsl:attribute>
<xsl:apply-templates select="node()|#*|text()"/>
</shortdesc>
</xsl:for-each>
<conbody>
<!-- the logic of #id/#group attributes is not clear -->
<xsl:apply-templates select="*[not(starts-with(local-name(),'r')) ]"/>
</conbody>
<!-- apply recursive -->
<xsl:apply-templates select="*[matches(local-name(),'r[3-9]')]"/>
</concept>
</xsl:when>
<xsl:when test="*[not(matches(local-name(),'r[3-9]'))]">
<concept>
<xsl:choose>
<xsl:when test="not(#id)">
<xsl:attribute name="id">
<xsl:value-of select="'concept'"/>
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="(#id ='')">
<xsl:attribute name="id">
<xsl:value-of select="'concept'"/>
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="(#id !='')">
<xsl:attribute name="id">
<xsl:value-of select="#id"/>
</xsl:attribute>
</xsl:when>
</xsl:choose>
<xsl:attribute name="xml:lang">
<xsl:value-of select="'en'"/>
</xsl:attribute>
<title>
<xsl:for-each select="child::rtit">
<xsl:attribute name="id">
<xsl:value-of select="#id"/>
</xsl:attribute>
<xsl:apply-templates select="node()|#*|text()"/>
</xsl:for-each>
</title>
<xsl:for-each select="child::subtitle">
<shortdesc>
<xsl:attribute name="id">
<xsl:value-of select="#id"/>
</xsl:attribute>
<xsl:apply-templates select="node()|#*|text()"/>
</shortdesc>
</xsl:for-each>
<conbody>
<xsl:apply-templates/>
</conbody>
</concept>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="rtit"/>
</xsl:stylesheet>

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?

XSLT1.0 replace multiple occurences of char with <br />

Have the following template that I use with xsl:call-template, but I need to use it to replace a ~ with <br />. I can get it to work with none HTML replacements but not when I try to use <br /> or &NewLine; or
. Any suggestions:
<xsl:template name="replace-substring">
<xsl:param name="original"/>
<xsl:param name="substring"/>
<xsl:param name="replacement" select="''"/>
<xsl:variable name="first">
<xsl:choose>
<xsl:when test="contains($original, $substring)" >
<xsl:value-of select="substring-before($original, $substring)" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$original"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="middle">
<xsl:choose>
<xsl:when test="contains($original, $substring)">
<xsl:value-of select="$replacement" />
</xsl:when>
<xsl:otherwise>
<xsl:text></xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="last">
<xsl:choose>
<xsl:when test="contains($original, $substring)">
<xsl:choose>
<xsl:when test="contains(substring-after($original, $substring),
$substring)">
<xsl:call-template name="replace-substring">
<xsl:with-param name="original">
<xsl:value-of select="substring-after($original, $substring)"/>
</xsl:with-param>
<xsl:with-param name="substring">
<xsl:value-of select="$substring"/>
</xsl:with-param>
<xsl:with-param name="replacement">
<xsl:value-of select="$replacement"/>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring-after($original, $substring)" />
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:text></xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="concat($first, $middle, $last)"/>
</xsl:template>
It's hard to tell what's going on with the first, middle, and last variables but you should be able to just use a literal <br/> in your param...
XML
<test>one~two~three</test>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="test">
<xsl:copy>
<xsl:call-template name="replace-char"/>
</xsl:copy>
</xsl:template>
<xsl:template name="replace-char">
<xsl:param name="char" select="'~'"/>
<xsl:param name="replacement"><br/></xsl:param>
<xsl:param name="string" select="."/>
<xsl:variable name="remaining" select="substring-after($string,$char)"/>
<xsl:value-of select="substring-before(concat($string,$char),$char)"/>
<xsl:if test="contains($string,$char)">
<xsl:copy-of select="$replacement"/>
</xsl:if>
<xsl:if test="$remaining">
<xsl:call-template name="replace-char">
<xsl:with-param name="string" select="$remaining"/>
<xsl:with-param name="char" select="$char"/>
<xsl:with-param name="replacement" select="$replacement"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Output
<test>one<br/>two<br/>three</test>

XSLT count of items meeting a calculated value

I have a set of XML data that I'm trying to go through and determine how many items have a date of less than 1 week old.
DATA:
<events>
<event>
<eventDate>20110504</date>
<description>whatever</description>
</event>
<event>
<eventDate>20110720</date>
<description>whatever</description>
</event>
.
.
.
<event>
<eventDate>20111210</date>
<description>whatever</description>
</event>
</events>
XSLT:
<xsl:variable name="events" select="sc:item('/sitecore/content/Home/Upcoming Events',.)" />
<xsl:variable name="now" select="dateutil:get_IsoNow()" />
<xsl:variable name="counter" select="0" />
<xsl:template match="*">
<xsl:apply-templates select="$sc_item" mode="main"/>
</xsl:template>
<xsl:template match="*" mode="main">
<xsl:choose>
<xsl:when test="count($events/item) > 0">
<xsl:for-each select="$events/item">
<xsl:sort select="sc:fld('eventDate',.)" order="ascending"/>
<xsl:variable name="date_difference">
<xsl:call-template name="date-difference">
<xsl:with-param name="item-year" select="substring(sc:fld('eventDate',.),1,4)" />
<xsl:with-param name="item-month" select="substring(sc:fld('eventDate',.),5,2)" />
<xsl:with-param name="item-day" select="substring(sc:fld('eventDate',.),7,2)" />
<xsl:with-param name="today-year" select="substring(substring($now,1,8),1,4)" />
<xsl:with-param name="today-month" select="substring(substring($now,1,8),5,2)" />
<xsl:with-param name="today-day" select="substring(substring($now,1,8),7,2)" />
</xsl:call-template>
</xsl:variable>
<xsl:if test="($date_difference < 8)">
<p>
<sc:text field="eventDate" /><br />
<sc:text field="description" />
</p>
**** Increment a counter variable ****
$counter++
</xsl:if>
</xsl:for-each>
**** Check the counter variable ****
<xsl:if test="($counter = 0)">
<p>No upcoming events are scheduled at this time.</p>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<p>No upcoming events are scheduled at this time.</p>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="date-difference">
<xsl:param name="item-year" />
<xsl:param name="item-month" />
<xsl:param name="item-day" />
<xsl:param name="today-year" />
<xsl:param name="today-month" />
<xsl:param name="today-day" />
<xsl:variable name="jul-item">
<xsl:call-template name="calculate-julian-day">
<xsl:with-param name="year" select="$item-year" />
<xsl:with-param name="month" select="$item-month" />
<xsl:with-param name="day" select="$item-day" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="jul-today">
<xsl:call-template name="calculate-julian-day">
<xsl:with-param name="year" select="$today-year" />
<xsl:with-param name="month" select="$today-month" />
<xsl:with-param name="day" select="$today-day" />
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$jul-today - $jul-item" />
</xsl:template>
<xsl:template name="calculate-julian-day">
<xsl:param name="year" />
<xsl:param name="month" />
<xsl:param name="day" />
<xsl:variable name="a" select="floor((14 - $month) div 12)" />
<xsl:variable name="y" select="$year + 4800 - $a" />
<xsl:variable name="m" select="$month + 12 * $a - 3" />
<xsl:value-of select="$day + floor((153 * $m + 2) div 5) + $y * 365 + floor($y div 4) - floor($y div 100) + floor($y div 400) - 32045" />
</xsl:template>
I know that I can't change the value of a variable in XSLT since they are actually constants.
I know that I need to use recursion of some sort.
I just can't figure out how to do this... I am truly stumped.
Could someone please help?
Couldn't you determine the string value of a "one week ago" date, then do a textual comparison using XPath?
count(string(event/eventDate) > $oneweekagodatestring)
Replace in your code this:
L o n g C o d e
**** Increment a counter variable ****
$counter++
with:
<xsl:variable name="vHits">
L o n g C o d e
<!-- If the condition is true -->
<xsl:text>1</xsl:text>
</xsl:variable>
and this code:
**** Check the counter variable ****
<xsl:if test="($counter = 0)">
<p>No upcoming events are scheduled at this time.</p>
</xsl:if>
with:
<xsl:if test="(string-length($vHits = 0)">
<p>No upcoming events are scheduled at this time.</p>
</xsl:if>
Complete code example:
This transformation demonstrates "counter-less" computing with XSLT :)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:variable name="vHits">
<xsl:apply-templates/>
</xsl:variable>
<xsl:value-of select="string-length($vHits)"/>
<xsl:text> numbers fulfil x^2 <= 10</xsl:text>
</xsl:template>
<xsl:template match="num">
<xsl:if test="not(. * . > 10)">1</xsl:if>
</xsl:template>
</xsl:stylesheet>
When applied on this XML document:
<nums>
<num>01</num>
<num>02</num>
<num>03</num>
<num>04</num>
<num>05</num>
<num>06</num>
<num>07</num>
<num>08</num>
<num>09</num>
<num>10</num>
</nums>
the wanted, correct result is produced:
3 numbers fulfil x^2 <= 10
If you are using Sitecore you can always use some of the built-in date functions to get year,month and day out without resorting to processing substrings etc.
<xsl:variable name="selectedDate">20111212</xsl:variable>
<xsl:variable name="isoSelectedDate" select="date:ToIsoDate(date:ParseDateTime($selectedDate,date:IsoDateToDateTime(sc:isoNow())))"/>
<xsl:variable name="day" select="sc:day($isoSelectedDate)"/>
<xsl:variable name="month" select="sc:month($isoSelectedDate)"/>
<xsl:variable name="year" select="sc:year($isoSelectedDate)"/>
I think Dimitre's answer works well but this may increase the readability slightly :)
I ended up using the "one week ago" date suggestion. It took quite a bit of work to come up with the template to create the variable for "$oneweekagodatestring". However, I got it working:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sc="http://www.sitecore.net/sc"
xmlns:dot="http://www.sitecore.net/dot"
xmlns:dateutil="http://www.sitecore.net/dateutil"
exclude-result-prefixes="dot sc dateutil">
<!-- output directives -->
<xsl:output method="html" indent="no" encoding="UTF-8" />
<!-- parameters -->
<xsl:param name="lang" select="''"/>
<xsl:param name="id" select="''"/>
<xsl:param name="sc_item"/>
<xsl:param name="sc_currentitem"/>
<!-- variables -->
<xsl:variable name="events" select="sc:item('/sitecore/content/Home/About/News Center/Upcoming Events',.)" />
<xsl:variable name="now" select="dateutil:get_IsoNow()" />
<!-- entry point -->
<xsl:template match="*">
<xsl:apply-templates select="$sc_item" mode="main"/>
</xsl:template>
<!--==============================================================-->
<!-- main -->
<!--==============================================================-->
<xsl:template match="*" mode="main">
<xsl:variable name="current_date">
<xsl:call-template name="adjust-date">
<xsl:with-param name="date" select="substring-before($now,'T')"/>
<xsl:with-param name="days" select="-7"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="count($events/item[sc:fld('Event Title',.)!='' and substring-before(sc:fld('Event Date',.),'T') > $current_date]) > 0">
<xsl:for-each select="$events/item[sc:fld('Event Title',.)!='' and substring-before(sc:fld('Event Date',.),'T') > $current_date]">
<xsl:sort select="sc:fld('Event Date',.)" order="ascending"/>
<p>Output for event information goes here.</p>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<p>No upcoming events are scheduled at this time.</p>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!--======================================================================-->
<!-- Add or subtract days to or from a date -->
<!-- -->
<!-- This template is from Boris Gomiunik. I found it here: -->
<!-- http://www.sharepointboris.net/2008/11/xsl-template-for-adding-days/ -->
<!--======================================================================-->
<xsl:template name="adjust-date">
<xsl:param name="date"/>
<xsl:param name="days"/>
<xsl:param name="oldMonth"><xsl:value-of select="substring($date,5,2)"/></xsl:param>
<xsl:param name="oldYear"><xsl:value-of select="substring($date,1,4)"/></xsl:param>
<xsl:param name="oldDay"><xsl:value-of select="substring($date,7,2)"/></xsl:param>
<xsl:param name="newMonth">
<xsl:choose>
<xsl:when test="$oldMonth = '01'">
<xsl:choose>
<xsl:when test="number($oldDay) + $days <= 31">01</xsl:when>
<xsl:otherwise>02</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '02'">
<xsl:choose>
<xsl:when test="($oldYear mod 4 = 0 and number($oldDay) + $days <= 29) or ($oldYear mod 4 != 0 and number($oldDay) + $days <= 28)">02</xsl:when>
<xsl:otherwise>03</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '03'">
<xsl:choose>
<xsl:when test="number($oldDay) + $days <= 31">03</xsl:when>
<xsl:otherwise>04</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '04'">
<xsl:choose>
<xsl:when test="number($oldDay) + $days <= 30">04</xsl:when>
<xsl:otherwise>05</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '05'">
<xsl:choose>
<xsl:when test="number($oldDay) + $days <= 31">05</xsl:when>
<xsl:otherwise>06</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '06'">
<xsl:choose>
<xsl:when test="number($oldDay) + $days <= 30">06</xsl:when>
<xsl:otherwise>07</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '07'">
<xsl:choose>
<xsl:when test="number($oldDay) + $days <= 31">07</xsl:when>
<xsl:otherwise>08</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '08'">
<xsl:choose>
<xsl:when test="number($oldDay) + $days <= 31">08</xsl:when>
<xsl:otherwise>09</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '09'">
<xsl:choose>
<xsl:when test="number($oldDay) + $days <= 30">09</xsl:when>
<xsl:otherwise>10</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '10'">
<xsl:choose>
<xsl:when test="number($oldDay) + $days <= 31">10</xsl:when>
<xsl:otherwise>11</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '11'">
<xsl:choose>
<xsl:when test="number($oldDay) + $days <= 30">11</xsl:when>
<xsl:otherwise>12</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '12'">
<xsl:choose>
<xsl:when test="number($oldDay) + $days <= 31">12</xsl:when>
<xsl:otherwise>01</xsl:otherwise>
</xsl:choose>
</xsl:when>
</xsl:choose>
</xsl:param>
<xsl:param name="newYear">
<xsl:choose>
<xsl:when test="$oldMonth = '12' and (number($oldDay) + $days) >= 31"><xsl:value-of select="number($oldYear) + 1"/></xsl:when>
<xsl:otherwise><xsl:value-of select="$oldYear"/></xsl:otherwise>
</xsl:choose>
</xsl:param>
<xsl:param name="newDay">
<xsl:choose>
<xsl:when test="$oldMonth = '01'">
<xsl:choose>
<xsl:when test="$newMonth = $oldMonth"><xsl:value-of select="number($oldDay) + $days"/></xsl:when>
<xsl:otherwise><xsl:value-of select="number($oldDay) + $days - 31"/></xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '02'">
<xsl:choose>
<xsl:when test="$newMonth = $oldMonth"><xsl:value-of select="number($oldDay) + $days"/></xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$oldYear mod 4 = 0">
<xsl:value-of select="number($oldDay) + $days - 29"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="number($oldDay) + $days - 28"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '03'">
<xsl:choose>
<xsl:when test="$newMonth = $oldMonth"><xsl:value-of select="number($oldDay) + $days"/></xsl:when>
<xsl:otherwise><xsl:value-of select="number($oldDay) + $days - 31"/></xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '04'">
<xsl:choose>
<xsl:when test="$newMonth = $oldMonth"><xsl:value-of select="number($oldDay) + $days"/></xsl:when>
<xsl:otherwise><xsl:value-of select="number($oldDay) + $days - 30"/></xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '05'">
<xsl:choose>
<xsl:when test="$newMonth = $oldMonth"><xsl:value-of select="number($oldDay) + $days"/></xsl:when>
<xsl:otherwise><xsl:value-of select="number($oldDay) + $days - 31"/></xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '06'">
<xsl:choose>
<xsl:when test="$newMonth = $oldMonth"><xsl:value-of select="number($oldDay) + $days"/></xsl:when>
<xsl:otherwise><xsl:value-of select="number($oldDay) + $days - 30"/></xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '07'">
<xsl:choose>
<xsl:when test="$newMonth = $oldMonth"><xsl:value-of select="number($oldDay) + $days"/></xsl:when>
<xsl:otherwise><xsl:value-of select="number($oldDay) + $days - 31"/></xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '08'">
<xsl:choose>
<xsl:when test="$newMonth = $oldMonth"><xsl:value-of select="number($oldDay) + $days"/></xsl:when>
<xsl:otherwise><xsl:value-of select="number($oldDay) + $days - 31"/></xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '09'">
<xsl:choose>
<xsl:when test="$newMonth = $oldMonth"><xsl:value-of select="number($oldDay) + $days"/></xsl:when>
<xsl:otherwise><xsl:value-of select="number($oldDay) + $days - 30"/></xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '10'">
<xsl:choose>
<xsl:when test="$newMonth = $oldMonth"><xsl:value-of select="number($oldDay) + $days"/></xsl:when>
<xsl:otherwise><xsl:value-of select="number($oldDay) + $days - 31"/></xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '11'">
<xsl:choose>
<xsl:when test="$newMonth = $oldMonth"><xsl:value-of select="number($oldDay) + $days"/></xsl:when>
<xsl:otherwise><xsl:value-of select="number($oldDay) + $days - 30"/></xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$oldMonth = '12'">
<xsl:choose>
<xsl:when test="$newMonth = $oldMonth"><xsl:value-of select="number($oldDay) + $days"/></xsl:when>
<xsl:otherwise><xsl:value-of select="number($oldDay) + $days - 31"/></xsl:otherwise>
</xsl:choose>
</xsl:when>
</xsl:choose>
</xsl:param>
<xsl:value-of select="$newYear"/>
<xsl:value-of select="$newMonth" />
<xsl:if test="$newDay < 10">0</xsl:if><xsl:value-of select="$newDay"/>
</xsl:template>
</xsl:stylesheet>