skip to Main Content

I would like convert JSON which is part of XML to XML structure using XSLT1.0(reason is our aplication only supports XSLT1.0 version).
Could someone be able to check and let me know on the same. Thank you

XML(with JSON): Fom below example, under the code tag, there is JSON which to be converted.

<root>
<root>
    <order>131as</order>
    <type>se134</type>
    <num>15643</num>
    <curr>USD</curr>
    <code>{"desc":"Testing123","city":"Dubai","auth":"author","store":[{"quantity":1,"amount":2.00},{"quantity":100,"amount":-8.33},{"quantity":300,"amount":-15.00}]}</code>
</root>
<root>
    <order>231as</order>
    <type>se134</type>
    <num>15643</num>
    <curr>AED</curr>
    <code>{"desc":"testdesc","city":"SHarjah","auth":"Mohammad","amount":20.00,"shop":"test","store":[{"quantity":1,"amount":10.00},{"quantity":100,"amount":98.33},{"quantity":300,"amount":-1.00}]}</code>
</root>
<root>
    <order>331as</order>
    <type>se134</type>
    <num>15643</num>
    <curr>SAR</curr>
    <code/>
</root>
<root>
    <order>431as</order>
    <type>se134</type>
    <num>15643</num>
    <curr>USD</curr>
    <code/>
</root>
<root>
    <order>531as</order>
    <type>Tse134</type>
    <num>15643</num>
    <curr>AED</curr>
    <code>{"desc":"testdesc","city":"Abudabhi","auth":"Mr.121","amount":10.00,"shop":"testa","store":[{"quantity":71,"amount":10.00},{"quantity":100,"amount":95.33},{"quantity":300,"amount":-8.00}]}</code>
</root>

Expected output :

<root>
<root>
    <order>131as</order>
    <type>se134</type>
    <num>15643</num>
    <curr>USD</curr>
    <code>
        <root>
            <amount>10.0</amount>
            <auth>Mr.121</auth>
            <city>Abudabhi</city>
            <desc>testdesc</desc>
            <shop>testa</shop>
            <store>
                <element>
                    <amount>10.0</amount>
                    <quantity>71</quantity>
                </element>
                <element>
                    <amount>95.33</amount>
                    <quantity>100</quantity>
                </element>
                <element>
                    <amount>-8.0</amount>
                    <quantity>300</quantity>
                </element>
            </store>
        </root>
    </code>
</root>
<root>
    <order>231as</order>
    <type>se134</type>
    <num>15643</num>
    <curr>AED</curr>
    <code>
        <root>
            <amount>20.0</amount>
            <auth>Mohammad</auth>
            <city>SHarjah</city>
            <desc>testdesc</desc>
            <shop>test</shop>
            <store>
                <element>
                    <amount>10.0</amount>
                    <quantity>1</quantity>
                </element>
                <element>
                    <amount>98.33</amount>
                    <quantity>100</quantity>
                </element>
                <element>
                    <amount>-1.0</amount>
                    <quantity>300</quantity>
                </element>
            </store>
        </root>
    </code>
</root>
<root>
    <order>331as</order>
    <type>se134</type>
    <num>15643</num>
    <curr>SAR</curr>
    <code/>
</root>
<root>
    <order>431as</order>
    <type>se134</type>
    <num>15643</num>
    <curr>USD</curr>
    <code/>
</root>
<root>
    <order>531as</order>
    <type>Tse134</type>
    <num>15643</num>
    <curr>AED</curr>
    <code>
        <root>
            <amount>10.0</amount>
            <auth>Mr.121</auth>
            <city>Abudabhi</city>
            <desc>testdesc</desc>
            <shop>testa</shop>
            <store>
                <element>
                    <amount>10.0</amount>
                    <quantity>71</quantity>
                </element>
                <element>
                    <amount>95.33</amount>
                    <quantity>100</quantity>
                </element>
                <element>
                    <amount>-8.0</amount>
                    <quantity>300</quantity>
                </element>
            </store>
        </root>
    </code>
</root>

Tried using the below XSLT which i found in one of blog .

    <?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="'&quot;'"/>
    <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>

3

Answers


  1. Here is a something you could use as your starting point (actually, it’s almost complete, you only have to fill in some blanks). This follows what I said in the comment to your question: it is tailored specifically to your JSON’s structure.

    XSLT 1.0

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="code">
        <xsl:copy>
            <!-- extract values from  elements at the top level -->
            <desc>
                <xsl:value-of select="substring-before(substring-after(., '&quot;desc&quot;:&quot;'), '&quot;')" />
            </desc>
            <city>
                <xsl:value-of select="substring-before(substring-after(., '&quot;city&quot;:&quot;'), '&quot;')" />
            </city>
            <!-- ... continue for other elements at the top level -->
            
            <!-- process the array -->
            <store>
                 <xsl:call-template name="process-array">
                    <xsl:with-param name="array" select="substring-before(substring-after(., '['), ']')" />
                 </xsl:call-template>   
            </store>
        </xsl:copy>
    </xsl:template> 
    
    <xsl:template name="process-array">
        <xsl:param name="array"/>
        <xsl:param name="delimiter" select="'},{'"/>
        <xsl:variable name="object" select="substring-before(concat($array, ',{'), $delimiter)" />
        <xsl:if test="$object">
            <element>
                <quantity>
                    <xsl:value-of select="substring-before(substring-after($object, '&quot;quantity&quot;:'), ',')" />
                </quantity>
                <amount>
                    <xsl:value-of select="substring-after($object, '&quot;amount&quot;:')" />
                </amount>
            </element>
        </xsl:if>
        <xsl:if test="contains($array, $delimiter)">
            <!-- recursive call -->
            <xsl:call-template name="process-array">
                <xsl:with-param name="array" select="substring-after($array, $delimiter)"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
    
    </xsl:stylesheet>
    

    Applied to your input example, this will return:

    Result

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
       <root>
          <order>131as</order>
          <type>se134</type>
          <num>15643</num>
          <curr>USD</curr>
          <code>
             <desc>Testing123</desc>
             <city>Dubai</city>
             <store>
                <element>
                   <quantity>1</quantity>
                   <amount>2.00</amount>
                </element>
                <element>
                   <quantity>100</quantity>
                   <amount>-8.33</amount>
                </element>
                <element>
                   <quantity>300</quantity>
                   <amount>-15.00</amount>
                </element>
             </store>
          </code>
       </root>
       <root>
          <order>231as</order>
          <type>se134</type>
          <num>15643</num>
          <curr>AED</curr>
          <code>
             <desc>testdesc</desc>
             <city>SHarjah</city>
             <store>
                <element>
                   <quantity>1</quantity>
                   <amount>10.00</amount>
                </element>
                <element>
                   <quantity>100</quantity>
                   <amount>98.33</amount>
                </element>
                <element>
                   <quantity>300</quantity>
                   <amount>-1.00</amount>
                </element>
             </store>
          </code>
       </root>
       <root>
          <order>331as</order>
          <type>se134</type>
          <num>15643</num>
          <curr>SAR</curr>
          <code>
             <desc/>
             <city/>
             <store/>
          </code>
       </root>
       <root>
          <order>431as</order>
          <type>se134</type>
          <num>15643</num>
          <curr>USD</curr>
          <code>
             <desc/>
             <city/>
             <store/>
          </code>
       </root>
       <root>
          <order>531as</order>
          <type>Tse134</type>
          <num>15643</num>
          <curr>AED</curr>
          <code>
             <desc>testdesc</desc>
             <city>Abudabhi</city>
             <store>
                <element>
                   <quantity>71</quantity>
                   <amount>10.00</amount>
                </element>
                <element>
                   <quantity>100</quantity>
                   <amount>95.33</amount>
                </element>
                <element>
                   <quantity>300</quantity>
                   <amount>-8.00</amount>
                </element>
             </store>
          </code>
       </root>
    </root>
    
    Login or Signup to reply.
  2. Writing a correct and complete parser for JSON in pure XSLT 1.0 is a challenging task, but it can be done.

    In fact it has been done: the Rex parser generator from Gunther Rademacher at https://bottlecaps.de/rex/ will generate an XSLT parser for any grammar, and JSON is one of the grammars that comes "out of the box".

    Rex is an excellent piece of software that sadly suffers from appalling documentation (and from not being truly open source, though it is free to use).

    Login or Signup to reply.
  3. Using XSLT 3 is possible on many platforms (using e.g. Saxon HE Java, Saxon HE .NET, SaxonC HE, SaxonJS) and in XSLT 3 you can use e.g. json-to-xml and custom templates to achieve the result:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:fn="http://www.w3.org/2005/xpath-functions"
        exclude-result-prefixes="#all"
        expand-text="yes"
        version="3.0">
     
       <xsl:mode on-no-match="shallow-copy"/>
     
       <xsl:output method="xml" indent="yes"/>
     
       <xsl:template match="code[parse-json(.) instance of map(*)]">
         <xsl:copy>
           <xsl:apply-templates select="json-to-xml(.)!* => sort((), function($el) { $el/@key})" mode="json"/>
         </xsl:copy>
       </xsl:template>
       
       <xsl:mode name="json" on-no-match="shallow-copy"/>
       
       <xsl:template mode="json" match="fn:*[@key]">
         <xsl:element name="{@key}">
           <xsl:apply-templates mode="#current"/>
         </xsl:element>
       </xsl:template>
       
       <xsl:template mode="json" match="fn:array[@key]/fn:map[not(@key)]">
         <element>
           <xsl:apply-templates select="* => sort((), function($el) { $el/@key })" mode="#current"/>
         </element>
       </xsl:template>
       
       <xsl:template mode="json" match="/fn:map[not(@key)]">
         <root>
           <xsl:apply-templates select="* => sort((), function($el) { $el/@key })" mode="#current"/>
         </root>
       </xsl:template>
       
     </xsl:stylesheet>
    

    Sample .NET 7 console code to run the example is e.g.

    using net.liberty_development.SaxonHE11s9apiExtensions;
    using net.sf.saxon.s9api;
    
    var xml = """
              <root>
                <root>
                    <order>131as</order>
                    <type>se134</type>
                    <num>15643</num>
                    <curr>USD</curr>
                    <code>{"desc":"Testing123","city":"Dubai","auth":"author","store":[{"quantity":1,"amount":2.00},{"quantity":100,"amount":-8.33},{"quantity":300,"amount":-15.00}]}</code>
                </root>
                <root>
                    <order>231as</order>
                    <type>se134</type>
                    <num>15643</num>
                    <curr>AED</curr>
                    <code>{"desc":"testdesc","city":"SHarjah","auth":"Mohammad","amount":20.00,"shop":"test","store":[{"quantity":1,"amount":10.00},{"quantity":100,"amount":98.33},{"quantity":300,"amount":-1.00}]}</code>
                </root>
                <root>
                    <order>331as</order>
                    <type>se134</type>
                    <num>15643</num>
                    <curr>SAR</curr>
                    <code/>
                </root>
                <root>
                    <order>431as</order>
                    <type>se134</type>
                    <num>15643</num>
                    <curr>USD</curr>
                    <code/>
                </root>
                <root>
                    <order>531as</order>
                    <type>Tse134</type>
                    <num>15643</num>
                    <curr>AED</curr>
                    <code>{"desc":"testdesc","city":"Abudabhi","auth":"Mr.121","amount":10.00,"shop":"testa","store":[{"quantity":71,"amount":10.00},{"quantity":100,"amount":95.33},{"quantity":300,"amount":-8.00}]}</code>
                </root>
              </root>
              """;
    
    var xslt = """
               <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:fn="http://www.w3.org/2005/xpath-functions"
                exclude-result-prefixes="#all"
                expand-text="yes"
                version="3.0">
               
                 <xsl:mode on-no-match="shallow-copy"/>
               
                 <xsl:output method="xml" indent="yes"/>
               
                 <xsl:template match="code[parse-json(.) instance of map(*)]">
                   <xsl:copy>
                     <xsl:apply-templates select="json-to-xml(.)!* => sort((), function($el) { $el/@key})" mode="json"/>
                   </xsl:copy>
                 </xsl:template>
                 
                 <xsl:mode name="json" on-no-match="shallow-copy"/>
                 
                 <xsl:template mode="json" match="fn:*[@key]">
                   <xsl:element name="{@key}">
                     <xsl:apply-templates mode="#current"/>
                   </xsl:element>
                 </xsl:template>
                 
                 <xsl:template mode="json" match="fn:array[@key]/fn:map[not(@key)]">
                   <element>
                     <xsl:apply-templates select="* => sort((), function($el) { $el/@key })" mode="#current"/>
                   </element>
                 </xsl:template>
                 
                 <xsl:template mode="json" match="/fn:map[not(@key)]">
                   <root>
                     <xsl:apply-templates select="* => sort((), function($el) { $el/@key })" mode="#current"/>
                   </root>
                 </xsl:template>
                 
               </xsl:stylesheet>
               """;
    
    var processor = new Processor(false);
    
    var xsltCompiler = processor.newXsltCompiler();
    
    var xsltExecutable = xsltCompiler.compile(xslt.AsSource());
    
    var xslt30Transformer = xsltExecutable.load30();
    
    xslt30Transformer.transform(xml.AsSource(), processor.NewSerializer(Console.Out));
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search