INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Jobs

Converting JSON to XML using XSLT 1.0

Converting JSON to XML using XSLT 1.0

(OP)
Background: A customer with robust XML capability needs to interact with a well known online payment system that uses JSON as its lingua franca. There is no readily available, easy-to-use JSON parser on the system. The challenge to me was to see if I could somehow use XSLT to process the JSON response package. (Producing JSON using XSLT is almost trivially easy.) The customer's XML engine, provided by a major software vendor, is limited to XSLT 1.0.

I did quite a bit of online searching for a solution. At least two elegant solutions exist that use XSLT 2.0, but I was unable to find a reliable solution using XSLT 1.0; what I could find makes use of extensions, which I was also trying to avoid.

I have developed a two step solution which uses standard XSLT 1.0, without extensions.

The first step makes extensive use of recursion to do a left-to-right scan of a JSON string, using output method="text" to create a well-formed XML document that essentially restates the JSON, albiet in rather odd-looking XML.

The second step is a normal XML-to-XML transform that restructures the output of the first step into a more pleasing, and probably more useful, XML document.

There are some caveats.

JSON descriptions talk quite a bit about name:value pairs, but you should be aware that what JSON describes as a name is really just a string without any additional requirements. While most examples of JSON use name strings that can be directly translated to XML names (as defined in the W3C specification for XML), be aware that some modification of the JSON name string value may be necessary. In the illustrated process, this name manipulation is handled in the second step.

JSON strings allow escaped characters. In particular, the quote character (") can be embedded in a string using the notation \". In the illustrated process, this is not allowed and will result in output from the first step that is not well-formed. My customer did not need this capability, and I did not provide it in order to reduce recursion depth. One could treat strings in a manner similar to the way numerics are treated. Ask if you need help.

Here is the result from an example I found on json.org, a site that shows considerable anti-XML bigotry:

CODE --> JSON

{"web-app": {
  "servlet": [   
    {
      "servlet-name": "cofaxCDS",
      "servlet-class": "org.cofax.cds.CDSServlet",
      "init-param": {
        "configGlossary:installationAt": "Philadelphia, PA",
        "configGlossary:adminEmail": "ksm@pobox.com",
        "configGlossary:poweredBy": "Cofax",
        "configGlossary:poweredByIcon": "/images/cofax.gif",
        "configGlossary:staticPath": "/content/static",
        "templateProcessorClass": "org.cofax.WysiwygTemplate",
        "templateLoaderClass": "org.cofax.FilesTemplateLoader",
        "templatePath": "templates",
        "templateOverridePath": "",
        "defaultListTemplate": "listTemplate.htm",
        "defaultFileTemplate": "articleTemplate.htm",
        "useJSP": false,
        "jspListTemplate": "listTemplate.jsp",
        "jspFileTemplate": "articleTemplate.jsp",
        "cachePackageTagsTrack": 200,
        "cachePackageTagsStore": 200,
        "cachePackageTagsRefresh": 60,
        "cacheTemplatesTrack": 100,
        "cacheTemplatesStore": 50,
        "cacheTemplatesRefresh": 15,
        "cachePagesTrack": 200,
        "cachePagesStore": 100,
        "cachePagesRefresh": 10,
        "cachePagesDirtyRead": 10,
        "searchEngineListTemplate": "forSearchEnginesList.htm",
        "searchEngineFileTemplate": "forSearchEngines.htm",
        "searchEngineRobotsDb": "WEB-INF/robots.db",
        "useDataStore": true,
        "dataStoreClass": "org.cofax.SqlDataStore",
        "redirectionClass": "org.cofax.SqlRedirection",
        "dataStoreName": "cofax",
        "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
        "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
        "dataStoreUser": "sa",
        "dataStorePassword": "dataStoreTestQuery",
        "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
        "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
        "dataStoreInitConns": 10,
        "dataStoreMaxConns": 100,
        "dataStoreConnUsageLimit": 100,
        "dataStoreLogLevel": "debug",
        "maxUrlLength": 500}},
    {
      "servlet-name": "cofaxEmail",
      "servlet-class": "org.cofax.cds.EmailServlet",
      "init-param": {
      "mailHost": "mail1",
      "mailHostOverride": "mail2"}},
    {
      "servlet-name": "cofaxAdmin",
      "servlet-class": "org.cofax.cds.AdminServlet"},
 
    {
      "servlet-name": "fileServlet",
      "servlet-class": "org.cofax.cds.FileServlet"},
    {
      "servlet-name": "cofaxTools",
      "servlet-class": "org.cofax.cms.CofaxToolsServlet",
      "init-param": {
        "templatePath": "toolstemplates/",
        "log": 1,
        "logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
        "logMaxSize": "",
        "dataLog": 1,
        "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
        "dataLogMaxSize": "",
        "removePageCache": "/content/admin/remove?cache=pages&id=",
        "removeTemplateCache": "/content/admin/remove?cache=templates&id=",
        "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
        "lookInContext": 1,
        "adminGroupID": 4,
        "betaServer": true}}],
  "servlet-mapping": {
    "cofaxCDS": "/",
    "cofaxEmail": "/cofaxutil/aemail/*",
    "cofaxAdmin": "/admin/*",
    "fileServlet": "/static/*",
    "cofaxTools": "/tools/*"},
 
  "taglib": {
    "taglib-uri": "cofax.tld",
    "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} 

CODE --> Output.of.Step.1

<root>
    <object>
        <nameNode name="web-app"/>
        <object>
            <nameNode name="servlet"/>
            <array>
                <object>
                    <nameNode name="servlet-name"/>
                    <value type="string">
                        <![CDATA[cofaxCDS]]>
                    </value>
                    <nameNode name="servlet-class"/>
                    <value type="string">
                        <![CDATA[org.cofax.cds.CDSServlet]]>
                    </value>
                    <nameNode name="init-param"/>
                    <object>
                        <nameNode name="configGlossary:installationAt"/>
                        <value type="string">
                            <![CDATA[Philadelphia, PA]]>
                        </value>
                        <nameNode name="configGlossary:adminEmail"/>
                        <value type="string">
                            <![CDATA[ksm@pobox.com]]>
                        </value>
                        <nameNode name="configGlossary:poweredBy"/>
                        <value type="string">
                            <![CDATA[Cofax]]>
                        </value>
                        <nameNode name="configGlossary:poweredByIcon"/>
                        <value type="string">
                            <![CDATA[/images/cofax.gif]]>
                        </value>
                        <nameNode name="configGlossary:staticPath"/>
                        <value type="string">
                            <![CDATA[/content/static]]>
                        </value>
                        <nameNode name="templateProcessorClass"/>
                        <value type="string">
                            <![CDATA[org.cofax.WysiwygTemplate]]>
                        </value>
                        <nameNode name="templateLoaderClass"/>
                        <value type="string">
                            <![CDATA[org.cofax.FilesTemplateLoader]]>
                        </value>
                        <nameNode name="templatePath"/>
                        <value type="string">
                            <![CDATA[templates]]>
                        </value>
                        <nameNode name="templateOverridePath"/>
                        <value type="string">
                            <![CDATA[]]>
                        </value>
                        <nameNode name="defaultListTemplate"/>
                        <value type="string">
                            <![CDATA[listTemplate.htm]]>
                        </value>
                        <nameNode name="defaultFileTemplate"/>
                        <value type="string">
                            <![CDATA[articleTemplate.htm]]>
                        </value>
                        <nameNode name="useJSP"/>
                        <value type="false">false</value>
                        <nameNode name="jspListTemplate"/>
                        <value type="string">
                            <![CDATA[listTemplate.jsp]]>
                        </value>
                        <nameNode name="jspFileTemplate"/>
                        <value type="string">
                            <![CDATA[articleTemplate.jsp]]>
                        </value>
                        <nameNode name="cachePackageTagsTrack"/>
                        <value type="number">200</value>
                        <nameNode name="cachePackageTagsStore"/>
                        <value type="number">200</value>
                        <nameNode name="cachePackageTagsRefresh"/>
                        <value type="number">60</value>
                        <nameNode name="cacheTemplatesTrack"/>
                        <value type="number">100</value>
                        <nameNode name="cacheTemplatesStore"/>
                        <value type="number">50</value>
                        <nameNode name="cacheTemplatesRefresh"/>
                        <value type="number">15</value>
                        <nameNode name="cachePagesTrack"/>
                        <value type="number">200</value>
                        <nameNode name="cachePagesStore"/>
                        <value type="number">100</value>
                        <nameNode name="cachePagesRefresh"/>
                        <value type="number">10</value>
                        <nameNode name="cachePagesDirtyRead"/>
                        <value type="number">10</value>
                        <nameNode name="searchEngineListTemplate"/>
                        <value type="string">
                            <![CDATA[forSearchEnginesList.htm]]>
                        </value>
                        <nameNode name="searchEngineFileTemplate"/>
                        <value type="string">
                            <![CDATA[forSearchEngines.htm]]>
                        </value>
                        <nameNode name="searchEngineRobotsDb"/>
                        <value type="string">
                            <![CDATA[WEB-INF/robots.db]]>
                        </value>
                        <nameNode name="useDataStore"/>
                        <value type="true">true</value>
                        <nameNode name="dataStoreClass"/>
                        <value type="string">
                            <![CDATA[org.cofax.SqlDataStore]]>
                        </value>
                        <nameNode name="redirectionClass"/>
                        <value type="string">
                            <![CDATA[org.cofax.SqlRedirection]]>
                        </value>
                        <nameNode name="dataStoreName"/>
                        <value type="string">
                            <![CDATA[cofax]]>
                        </value>
                        <nameNode name="dataStoreDriver"/>
                        <value type="string">
                            <![CDATA[com.microsoft.jdbc.sqlserver.SQLServerDriver]]>
                        </value>
                        <nameNode name="dataStoreUrl"/>
                        <value type="string">
                            <![CDATA[jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon]]>
                        </value>
                        <nameNode name="dataStoreUser"/>
                        <value type="string">
                            <![CDATA[sa]]>
                        </value>
                        <nameNode name="dataStorePassword"/>
                        <value type="string">
                            <![CDATA[dataStoreTestQuery]]>
                        </value>
                        <nameNode name="dataStoreTestQuery"/>
                        <value type="string">
                            <![CDATA[SET NOCOUNT ON;select test='test';]]>
                        </value>
                        <nameNode name="dataStoreLogFile"/>
                        <value type="string">
                            <![CDATA[/usr/local/tomcat/logs/datastore.log]]>
                        </value>
                        <nameNode name="dataStoreInitConns"/>
                        <value type="number">10</value>
                        <nameNode name="dataStoreMaxConns"/>
                        <value type="number">100</value>
                        <nameNode name="dataStoreConnUsageLimit"/>
                        <value type="number">100</value>
                        <nameNode name="dataStoreLogLevel"/>
                        <value type="string">
                            <![CDATA[debug]]>
                        </value>
                        <nameNode name="maxUrlLength"/>
                        <value type="number">500</value>
                    </object>
                </object>
                <object>
                    <nameNode name="servlet-name"/>
                    <value type="string">
                        <![CDATA[cofaxEmail]]>
                    </value>
                    <nameNode name="servlet-class"/>
                    <value type="string">
                        <![CDATA[org.cofax.cds.EmailServlet]]>
                    </value>
                    <nameNode name="init-param"/>
                    <object>
                        <nameNode name="mailHost"/>
                        <value type="string">
                            <![CDATA[mail1]]>
                        </value>
                        <nameNode name="mailHostOverride"/>
                        <value type="string">
                            <![CDATA[mail2]]>
                        </value>
                    </object>
                </object>
                <object>
                    <nameNode name="servlet-name"/>
                    <value type="string">
                        <![CDATA[cofaxAdmin]]>
                    </value>
                    <nameNode name="servlet-class"/>
                    <value type="string">
                        <![CDATA[org.cofax.cds.AdminServlet]]>
                    </value>
                </object>
                <object>
                    <nameNode name="servlet-name"/>
                    <value type="string">
                        <![CDATA[fileServlet]]>
                    </value>
                    <nameNode name="servlet-class"/>
                    <value type="string">
                        <![CDATA[org.cofax.cds.FileServlet]]>
                    </value>
                </object>
                <object>
                    <nameNode name="servlet-name"/>
                    <value type="string">
                        <![CDATA[cofaxTools]]>
                    </value>
                    <nameNode name="servlet-class"/>
                    <value type="string">
                        <![CDATA[org.cofax.cms.CofaxToolsServlet]]>
                    </value>
                    <nameNode name="init-param"/>
                    <object>
                        <nameNode name="templatePath"/>
                        <value type="string">
                            <![CDATA[toolstemplates/]]>
                        </value>
                        <nameNode name="log"/>
                        <value type="number">1</value>
                        <nameNode name="logLocation"/>
                        <value type="string">
                            <![CDATA[/usr/local/tomcat/logs/CofaxTools.log]]>
                        </value>
                        <nameNode name="logMaxSize"/>
                        <value type="string">
                            <![CDATA[]]>
                        </value>
                        <nameNode name="dataLog"/>
                        <value type="number">1</value>
                        <nameNode name="dataLogLocation"/>
                        <value type="string">
                            <![CDATA[/usr/local/tomcat/logs/dataLog.log]]>
                        </value>
                        <nameNode name="dataLogMaxSize"/>
                        <value type="string">
                            <![CDATA[]]>
                        </value>
                        <nameNode name="removePageCache"/>
                        <value type="string">
                            <![CDATA[/content/admin/remove?cache=pages&id=]]>
                        </value>
                        <nameNode name="removeTemplateCache"/>
                        <value type="string">
                            <![CDATA[/content/admin/remove?cache=templates&id=]]>
                        </value>
                        <nameNode name="fileTransferFolder"/>
                        <value type="string">
                            <![CDATA[/usr/local/tomcat/webapps/content/fileTransferFolder]]>
                        </value>
                        <nameNode name="lookInContext"/>
                        <value type="number">1</value>
                        <nameNode name="adminGroupID"/>
                        <value type="number">4</value>
                        <nameNode name="betaServer"/>
                        <value type="true">true</value>
                    </object>
                </object>
            </array>
            <nameNode name="servlet-mapping"/>
            <object>
                <nameNode name="cofaxCDS"/>
                <value type="string">
                    <![CDATA[/]]>
                </value>
                <nameNode name="cofaxEmail"/>
                <value type="string">
                    <![CDATA[/cofaxutil/aemail/*]]>
                </value>
                <nameNode name="cofaxAdmin"/>
                <value type="string">
                    <![CDATA[/admin/*]]>
                </value>
                <nameNode name="fileServlet"/>
                <value type="string">
                    <![CDATA[/static/*]]>
                </value>
                <nameNode name="cofaxTools"/>
                <value type="string">
                    <![CDATA[/tools/*]]>
                </value>
            </object>
            <nameNode name="taglib"/>
            <object>
                <nameNode name="taglib-uri"/>
                <value type="string">
                    <![CDATA[cofax.tld]]>
                </value>
                <nameNode name="taglib-location"/>
                <value type="string">
                    <![CDATA[/WEB-INF/tlds/cofax.tld]]>
                </value>
            </object>
        </object>
    </object>
</root> 

CODE --> Output.of.Step.2

<root>
    <object>
        <web-app>
            <servlet>
                <object>
                    <servlet-name>cofaxCDS</servlet-name>
                    <servlet-class>org.cofax.cds.CDSServlet</servlet-class>
                    <init-param>
                        <configGlossary-installationAt>Philadelphia, PA</configGlossary-installationAt>
                        <configGlossary-adminEmail>ksm@pobox.com</configGlossary-adminEmail>
                        <configGlossary-poweredBy>Cofax</configGlossary-poweredBy>
                        <configGlossary-poweredByIcon>/images/cofax.gif</configGlossary-poweredByIcon>
                        <configGlossary-staticPath>/content/static</configGlossary-staticPath>
                        <templateProcessorClass>org.cofax.WysiwygTemplate</templateProcessorClass>
                        <templateLoaderClass>org.cofax.FilesTemplateLoader</templateLoaderClass>
                        <templatePath>templates</templatePath>
                        <templateOverridePath/>
                        <defaultListTemplate>listTemplate.htm</defaultListTemplate>
                        <defaultFileTemplate>articleTemplate.htm</defaultFileTemplate>
                        <useJSP>false</useJSP>
                        <jspListTemplate>listTemplate.jsp</jspListTemplate>
                        <jspFileTemplate>articleTemplate.jsp</jspFileTemplate>
                        <cachePackageTagsTrack>200</cachePackageTagsTrack>
                        <cachePackageTagsStore>200</cachePackageTagsStore>
                        <cachePackageTagsRefresh>60</cachePackageTagsRefresh>
                        <cacheTemplatesTrack>100</cacheTemplatesTrack>
                        <cacheTemplatesStore>50</cacheTemplatesStore>
                        <cacheTemplatesRefresh>15</cacheTemplatesRefresh>
                        <cachePagesTrack>200</cachePagesTrack>
                        <cachePagesStore>100</cachePagesStore>
                        <cachePagesRefresh>10</cachePagesRefresh>
                        <cachePagesDirtyRead>10</cachePagesDirtyRead>
                        <searchEngineListTemplate>forSearchEnginesList.htm</searchEngineListTemplate>
                        <searchEngineFileTemplate>forSearchEngines.htm</searchEngineFileTemplate>
                        <searchEngineRobotsDb>WEB-INF/robots.db</searchEngineRobotsDb>
                        <useDataStore>true</useDataStore>
                        <dataStoreClass>org.cofax.SqlDataStore</dataStoreClass>
                        <redirectionClass>org.cofax.SqlRedirection</redirectionClass>
                        <dataStoreName>cofax</dataStoreName>
                        <dataStoreDriver>com.microsoft.jdbc.sqlserver.SQLServerDriver</dataStoreDriver>
                        <dataStoreUrl>jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon</dataStoreUrl>
                        <dataStoreUser>sa</dataStoreUser>
                        <dataStorePassword>dataStoreTestQuery</dataStorePassword>
                        <dataStoreTestQuery>SET NOCOUNT ON;select test='test';</dataStoreTestQuery>
                        <dataStoreLogFile>/usr/local/tomcat/logs/datastore.log</dataStoreLogFile>
                        <dataStoreInitConns>10</dataStoreInitConns>
                        <dataStoreMaxConns>100</dataStoreMaxConns>
                        <dataStoreConnUsageLimit>100</dataStoreConnUsageLimit>
                        <dataStoreLogLevel>debug</dataStoreLogLevel>
                        <maxUrlLength>500</maxUrlLength>
                    </init-param>
                </object>
                <object>
                    <servlet-name>cofaxEmail</servlet-name>
                    <servlet-class>org.cofax.cds.EmailServlet</servlet-class>
                    <init-param>
                        <mailHost>mail1</mailHost>
                        <mailHostOverride>mail2</mailHostOverride>
                    </init-param>
                </object>
                <object>
                    <servlet-name>cofaxAdmin</servlet-name>
                    <servlet-class>org.cofax.cds.AdminServlet</servlet-class>
                </object>
                <object>
                    <servlet-name>fileServlet</servlet-name>
                    <servlet-class>org.cofax.cds.FileServlet</servlet-class>
                </object>
                <object>
                    <servlet-name>cofaxTools</servlet-name>
                    <servlet-class>org.cofax.cms.CofaxToolsServlet</servlet-class>
                    <init-param>
                        <templatePath>toolstemplates/</templatePath>
                        <log>1</log>
                        <logLocation>/usr/local/tomcat/logs/CofaxTools.log</logLocation>
                        <logMaxSize/>
                        <dataLog>1</dataLog>
                        <dataLogLocation>/usr/local/tomcat/logs/dataLog.log</dataLogLocation>
                        <dataLogMaxSize/>
                        <removePageCache>/content/admin/remove?cache=pages&id=</removePageCache>
                        <removeTemplateCache>/content/admin/remove?cache=templates&id=</removeTemplateCache>
                        <fileTransferFolder>/usr/local/tomcat/webapps/content/fileTransferFolder</fileTransferFolder>
                        <lookInContext>1</lookInContext>
                        <adminGroupID>4</adminGroupID>
                        <betaServer>true</betaServer>
                    </init-param>
                </object>
            </servlet>
            <servlet-mapping>
                <cofaxCDS>/</cofaxCDS>
                <cofaxEmail>/cofaxutil/aemail/*</cofaxEmail>
                <cofaxAdmin>/admin/*</cofaxAdmin>
                <fileServlet>/static/*</fileServlet>
                <cofaxTools>/tools/*</cofaxTools>
            </servlet-mapping>
            <taglib>
                <taglib-uri>cofax.tld</taglib-uri>
                <taglib-location>/WEB-INF/tlds/cofax.tld</taglib-location>
            </taglib>
        </web-app>
    </object>
</root> 

CODE --> XSLT.for.Step.1

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>
<xsl:param name="jsonString" select="{ }"/>  <!-- you have to decide how you will get the JSON string into the transform -->

<xsl:template match="/">
<xsl:value-of disable-output-escaping="yes" select="concat('&lt;','root','&gt;')"/>
<xsl:call-template name="parseNextToken">
	<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="$jsonString"/></xsl:call-template></xsl:with-param>
</xsl:call-template>
<xsl:value-of disable-output-escaping="yes" select="concat('&lt;','/root','&gt;')"/>
</xsl:template>

<xsl:template name="parseNextToken">
<xsl:param name="remaining" select="'"/>
<xsl:param name="operandStack" select="','"/>

<xsl:variable name="operandChar" select="substring($remaining,1,1)"/>

<xsl:choose>
<xsl:when test="string-length($remaining) = 0"></xsl:when>

<xsl:when test="$operandChar = '{'">
<xsl:value-of disable-output-escaping="yes" select="concat('&lt;','object','&gt;')"/>
<xsl:call-template name="parseNextToken">
	<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($remaining,2)"/></xsl:call-template></xsl:with-param>
	<xsl:with-param name="operandStack" select="concat($operandChar,$operandStack)"/>
</xsl:call-template>
</xsl:when>

<xsl:when test="$operandChar = '}'">
<xsl:value-of disable-output-escaping="yes" select="concat('&lt;','/object','&gt;')"/>
<xsl:call-template name="parseNextToken">
	<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($remaining,2)"/></xsl:call-template></xsl:with-param>
	<xsl:with-param name="operandStack" select="substring($operandStack,2)"/>
</xsl:call-template>
</xsl:when>

<xsl:when test="$operandChar = '['">
<xsl:value-of disable-output-escaping="yes" select="concat('&lt;','array','&gt;')"/>
<xsl:call-template name="parseNextToken">
	<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($remaining,2)"/></xsl:call-template></xsl:with-param>
	<xsl:with-param name="operandStack" select="concat($operandChar,$operandStack)"/>
</xsl:call-template>
</xsl:when>

<xsl:when test="$operandChar = ']'">
<xsl:value-of disable-output-escaping="yes" select="concat('&lt;','/array','&gt;')"/>
<xsl:call-template name="parseNextToken">
	<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($remaining,2)"/></xsl:call-template></xsl:with-param>
	<xsl:with-param name="operandStack" select="substring($operandStack,2)"/>
</xsl:call-template>
</xsl:when>

<xsl:when test="$operandChar = '&quot;'">
<!-- if the top of the operand stack is a comma, then this must be name
     if the top of the operand stack is a [ or :, then this must be a string value -->
	<xsl:choose>
	<xsl:when test="substring($operandStack,1,1) = ',' or substring($operandStack,1,1) = '{'">  <!-- name -->
		<xsl:variable name="nameString" select="substring-before(substring($remaining,2),'&quot;')"/>
        <xsl:value-of disable-output-escaping="yes" select="concat('&lt;','nameNode name=&quot;',$nameString,'&quot;/&gt;')"/>
		<xsl:call-template name="parseNextToken">
			<xsl:with-param name="operandStack" select="concat(':',$operandStack)"/>
			<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring-after(substring-after(substring($remaining,2),'&quot;'),':')"/></xsl:call-template></xsl:with-param>
		</xsl:call-template>
	</xsl:when>
	<xsl:when test="substring($operandStack,1,1) = '['">  <!-- value in an array -->
		<xsl:variable name="theValue" select="substring-before(substring($remaining,2),'&quot;')"/>
		<xsl:variable name="afterTheValue"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring-after(substring($remaining,2),'&quot;')"/></xsl:call-template></xsl:variable>
		<xsl:variable name="remainingAfterValue"><xsl:choose><xsl:when test="substring($afterTheValue,1,1) = ','"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($afterTheValue,2)"/></xsl:call-template></xsl:when>
		                                                     <xsl:otherwise><xsl:value-of select="$afterTheValue"/></xsl:otherwise>
		                                         </xsl:choose>
	    </xsl:variable> <!-- $remainingAfterValue is used to swallow the comma in a series of values within an array -->
		<xsl:value-of disable-output-escaping="yes" select="concat('&lt;arrayItem type=&quot;string&quot;&gt;&lt;![CDATA[',$theValue,']]&gt;&lt;/arrayItem&gt;')"/>
		<xsl:call-template name="parseNextToken">
			<xsl:with-param name="operandStack" select="$operandStack"/> <!-- keep the bracket as the operator -->
			<xsl:with-param name="remaining" select="$afterTheValue"/>
		</xsl:call-template>
	</xsl:when>
	<xsl:when test="substring($operandStack,1,1) = ':'">  <!-- elementary value  -->
		<xsl:variable name="theValue" select="substring-before(substring($remaining,2),'&quot;')"/>
		<xsl:value-of disable-output-escaping="yes" select="concat('&lt;value type=&quot;string&quot;&gt;&lt;![CDATA[',$theValue,']]&gt;&lt;/value&gt;')"/>
		<xsl:call-template name="parseNextToken">
			<xsl:with-param name="operandStack" select="$operandStack"/>
			<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring-after(substring($remaining,2),'&quot;')"/></xsl:call-template></xsl:with-param>
		</xsl:call-template>
	</xsl:when>
	</xsl:choose>
</xsl:when>

<xsl:when test="$operandChar = ','">
	<xsl:variable name="nextOperandStack"><xsl:choose><xsl:when test="substring($operandStack,1,1) = '['"><xsl:value-of select="$operandStack"/></xsl:when>
	                                                  <xsl:otherwise><xsl:value-of select="concat(',',$operandStack)"/></xsl:otherwise>
	                                      </xsl:choose></xsl:variable>
	<xsl:call-template name="parseNextToken">
		<xsl:with-param name="operandStack" select="$nextOperandStack"/>
		<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($remaining,2)"/></xsl:call-template></xsl:with-param>
	</xsl:call-template>
</xsl:when>

<xsl:when test="contains('0123456789.-',$operandChar)">
	<xsl:variable name="numberString"><xsl:call-template name="getNumberString"><xsl:with-param name="theString" select="$remaining"/></xsl:call-template></xsl:variable>
	<xsl:variable name="afterNumberString"><xsl:call-template name="getAfterNumberString"><xsl:with-param name="theString" select="$remaining"/></xsl:call-template></xsl:variable>
	<xsl:choose>
	<xsl:when test="substring($operandStack,1,1) = '['">  <!-- value in an array -->
		<xsl:variable name="remainingAfterValue"><xsl:choose><xsl:when test="substring($afterNumberString,1,1) = ','"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($afterNumberString,2)"/></xsl:call-template></xsl:when>
		                                                     <xsl:otherwise><xsl:value-of select="$afterNumberString"/></xsl:otherwise>
		                                         </xsl:choose>
	    </xsl:variable> <!-- $remainingAfterValue is used to swallow the comma in a series of values within an array -->
		<xsl:value-of disable-output-escaping="yes" select="concat('&lt;arrayItem type=&quot;number&quot;>',$numberString,'&lt;/arrayItem>')"/>
		<xsl:call-template name="parseNextToken">
			<xsl:with-param name="operandStack" select="$operandStack"/> <!-- keep the bracket as the operator -->
			<xsl:with-param name="remaining" select="$remainingAfterValue"/>
		</xsl:call-template>
	</xsl:when>
	<xsl:when test="substring($operandStack,1,1) = ':'">  <!-- elementary value  -->
		<xsl:value-of disable-output-escaping="yes" select="concat('&lt;value type=&quot;number&quot;&gt;',$numberString,'&lt;/value&gt;')"/>
		<xsl:call-template name="parseNextToken">
			<xsl:with-param name="operandStack" select="$operandStack"/>
			<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="$afterNumberString"/></xsl:call-template></xsl:with-param>
		</xsl:call-template>
	</xsl:when>
	</xsl:choose> 
</xsl:when>

<xsl:when test="substring($remaining,1,4) = 'true' or substring($remaining,1,5) = 'false' or substring($remaining,1,4) = 'null'">
<xsl:variable name="keyword"><xsl:choose><xsl:when test="substring($remaining,1,4) = 'true'">true</xsl:when>
                                         <xsl:when test="substring($remaining,1,5) = 'false'">false</xsl:when>
										 <xsl:when test="substring($remaining,1,4) = 'null'">null</xsl:when></xsl:choose></xsl:variable>
	<xsl:value-of disable-output-escaping="yes" select="concat('&lt;value type=&quot;',$keyword,'&quot;&gt;',$keyword,'&lt;/value&gt;')"/>
	<xsl:call-template name="parseNextToken">
		<xsl:with-param name="operandStack" select="$operandStack"/>
		<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($remaining,string-length($keyword)+1)"/></xsl:call-template></xsl:with-param>
	</xsl:call-template>
</xsl:when>

<xsl:otherwise>
	<xsl:value-of disable-output-escaping="yes" select="concat('&lt;parseError&gt;',substring($remaining,1,1),'&lt;/parseError&gt;')"/>
	<xsl:call-template name="parseNextToken">
		<xsl:with-param name="operandStack" select="$operandStack"/>
		<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($remaining,2)"/></xsl:call-template></xsl:with-param>
	</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template name="stripLeadingWhitespace">
<xsl:param name="theString" select="'"/>
<xsl:choose>
<xsl:when test="string-length($theString) &gt; 0">
	<xsl:variable name="firstChar" select="substring($theString,1,1)"/>
	<xsl:variable name="remaining" select="substring($theString,2)"/>
	<xsl:choose>
	<xsl:when test="string-length(normalize-space($firstChar)) &gt; 0"><xsl:value-of select="$theString"/></xsl:when>
	<xsl:otherwise><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="$remaining"/></xsl:call-template></xsl:otherwise>
	</xsl:choose>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:template>

<xsl:template name="getNumberString">
<xsl:param name="theString" select="'"/>
<xsl:param name="outString" select="'"/>
<xsl:choose>
<xsl:when test="string-length($theString) &gt; 0">
	<xsl:choose>
	<xsl:when test="contains('0123456789.eE-+',substring($theString,1,1))"><xsl:call-template name="getNumberString">
	                                                                       <xsl:with-param name="theString" select="substring($theString,2)"/>
																		   <xsl:with-param name="outString" select="concat($outString,substring($theString,1,1))"/>
																		   </xsl:call-template></xsl:when>
	<xsl:otherwise><xsl:value-of select="$outString"/></xsl:otherwise>
	</xsl:choose>
</xsl:when>
<xsl:otherwise><xsl:value-of select="$outString"/></xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template name="getAfterNumberString">
<xsl:param name="theString" select="'"/>
<xsl:choose>
<xsl:when test="string-length($theString) &gt; 0">
	<xsl:choose>
	<xsl:when test="contains('0123456789.eE-+',substring($theString,1,1))"><xsl:call-template name="getAfterNumberString">
	                                                                       <xsl:with-param name="theString" select="substring($theString,2)"/>
																		   </xsl:call-template></xsl:when>
	<xsl:otherwise><xsl:value-of select="$theString"/></xsl:otherwise>
	</xsl:choose>
</xsl:when>
<xsl:otherwise></xsl:otherwise>
</xsl:choose>
</xsl:template>

</xsl:stylesheet> 

CODE --> XSLT.for.Step.2

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml" encoding="utf-8"/>

<xsl:template match="/">
<root><xsl:apply-templates select="*[local-name() != 'nameNode']"/></root>
</xsl:template>

<xsl:template match="value">
<xsl:variable name="nodeName"><xsl:call-template name="createNodeName"/></xsl:variable>
<xsl:element name="{$nodeName}"><xsl:value-of select="."/></xsl:element>
</xsl:template>

<xsl:template match="arrayItem">
<xsl:variable name="candidateNodeName"><xsl:choose>
                                <xsl:when test="local-name(parent::array[1]/preceding-sibling::*[1]) = 'nameNode'"><xsl:value-of select="parent::array[1]/preceding-sibling::*[1]/@name"/></xsl:when>
                                <xsl:otherwise><xsl:value-of select="local-name(.)"/></xsl:otherwise>
                              </xsl:choose></xsl:variable>
<xsl:variable name="nodeName"><xsl:value-of select="concat(translate(substring($candidateNodeName,1,1),'0123456789','xxxxxxxxxx'),translate(substring($candidateNodeName,2),'_ ','-'),'Item')"/></xsl:variable>
<xsl:element name="{$nodeName}"><xsl:value-of select="."/></xsl:element>
</xsl:template>

<xsl:template match="object|array">
<xsl:variable name="nodeName"><xsl:call-template name="createNodeName"/></xsl:variable>
<xsl:element name="{$nodeName}"><xsl:apply-templates select="*[local-name() != 'nameNode']"/></xsl:element>
</xsl:template>

<xsl:template name="createNodeName">
<xsl:variable name="candidateNodeName"><xsl:choose>
                                          <xsl:when test="local-name(preceding-sibling::*[1]) = 'nameNode'"><xsl:value-of select="preceding-sibling::*[1]/@name"/></xsl:when>
                                          <xsl:otherwise><xsl:value-of select="local-name(.)"/></xsl:otherwise>
                                       </xsl:choose></xsl:variable>
<!-- apply any adjustments necessary to get the JSON name to a valid name for an XML node.  
     As an example the following will ensure that the name will not begin with a digit or a space,
	 and that underscore and colon are converted to hyphen. -->
<xsl:variable name="actualNodeName"><xsl:value-of select="concat(translate(substring($candidateNodeName,1,1),'0123456789 ','xxxxxxxxxx'),translate(substring($candidateNodeName,2),':_ ','--'))"/></xsl:variable>
<xsl:value-of select="$actualNodeName"/>
</xsl:template>

</xsl:stylesheet> 

Please let me know if you find this useful.



Tom Morrison
Micro Focus

RE: Converting JSON to XML using XSLT 1.0

(OP)
It has been brought to my attention that the XSLT code was clipped. I am reposting the two XSLT.

CODE --> XSLT.for.Step.1

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

<xsl:template match="/">
<xsl:value-of disable-output-escaping="yes" select="concat('&lt;','root','&gt;')"/>
<xsl:call-template name="parseNextToken">
	<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="/json-string"/></xsl:call-template></xsl:with-param>
</xsl:call-template>
<xsl:value-of disable-output-escaping="yes" select="concat('&lt;','/root','&gt;')"/>
</xsl:template>

<xsl:template name="parseNextToken">
<xsl:param name="remaining" select="'"/>
<xsl:param name="operandStack" select="','"/>

<xsl:variable name="operandChar" select="substring($remaining,1,1)"/>

<xsl:choose>
<xsl:when test="string-length($remaining) = 0"></xsl:when>

<xsl:when test="$operandChar = '{'">
<xsl:value-of disable-output-escaping="yes" select="concat('&lt;','object','&gt;')"/>
<xsl:call-template name="parseNextToken">
	<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($remaining,2)"/></xsl:call-template></xsl:with-param>
	<xsl:with-param name="operandStack" select="concat($operandChar,$operandStack)"/>
</xsl:call-template>
</xsl:when>

<xsl:when test="$operandChar = '}'">
<xsl:value-of disable-output-escaping="yes" select="concat('&lt;','/object','&gt;')"/>
<xsl:call-template name="parseNextToken">
	<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($remaining,2)"/></xsl:call-template></xsl:with-param>
	<xsl:with-param name="operandStack" select="substring($operandStack,2)"/>
</xsl:call-template>
</xsl:when>

<xsl:when test="$operandChar = '['">
<xsl:value-of disable-output-escaping="yes" select="concat('&lt;','array','&gt;')"/>
<xsl:call-template name="parseNextToken">
	<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($remaining,2)"/></xsl:call-template></xsl:with-param>
	<xsl:with-param name="operandStack" select="concat($operandChar,$operandStack)"/>
</xsl:call-template>
</xsl:when>

<xsl:when test="$operandChar = ']'">
<xsl:value-of disable-output-escaping="yes" select="concat('&lt;','/array','&gt;')"/>
<xsl:call-template name="parseNextToken">
	<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($remaining,2)"/></xsl:call-template></xsl:with-param>
	<xsl:with-param name="operandStack" select="substring($operandStack,2)"/>
</xsl:call-template>
</xsl:when>

<xsl:when test="$operandChar = '&quot;'">
<!-- if the top of the operand stack is a comma, then this must be name
     if the top of the operand stack is a [ or :, then this must be a string value -->
	<xsl:choose>
	<xsl:when test="substring($operandStack,1,1) = ',' or substring($operandStack,1,1) = '{'">  <!-- name -->
		<xsl:variable name="nameString" select="substring-before(substring($remaining,2),'&quot;')"/>
        <xsl:value-of disable-output-escaping="yes" select="concat('&lt;','nameNode name=&quot;',$nameString,'&quot;/&gt;')"/>
		<xsl:call-template name="parseNextToken">
			<xsl:with-param name="operandStack" select="concat(':',$operandStack)"/>
			<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring-after(substring-after(substring($remaining,2),'&quot;'),':')"/></xsl:call-template></xsl:with-param>
		</xsl:call-template>
	</xsl:when>
	<xsl:when test="substring($operandStack,1,1) = '['">  <!-- value in an array -->
		<xsl:variable name="theValue" select="substring-before(substring($remaining,2),'&quot;')"/>
		<xsl:variable name="afterTheValue"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring-after(substring($remaining,2),'&quot;')"/></xsl:call-template></xsl:variable>
		<xsl:variable name="remainingAfterValue"><xsl:choose><xsl:when test="substring($afterTheValue,1,1) = ','"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($afterTheValue,2)"/></xsl:call-template></xsl:when>
		                                                     <xsl:otherwise><xsl:value-of select="$afterTheValue"/></xsl:otherwise>
		                                         </xsl:choose>
	    </xsl:variable> <!-- $remainingAfterValue is used to swallow the comma in a series of values within an array -->
		<xsl:value-of disable-output-escaping="yes" select="concat('&lt;arrayItem type=&quot;string&quot;&gt;&lt;![CDATA[',$theValue,']]&gt;&lt;/arrayItem&gt;')"/>
		<xsl:call-template name="parseNextToken">
			<xsl:with-param name="operandStack" select="$operandStack"/> <!-- keep the bracket as the operator -->
			<xsl:with-param name="remaining" select="$afterTheValue"/>
		</xsl:call-template>
	</xsl:when>
	<xsl:when test="substring($operandStack,1,1) = ':'">  <!-- elementary value  -->
		<xsl:variable name="theValue" select="substring-before(substring($remaining,2),'&quot;')"/>
		<xsl:value-of disable-output-escaping="yes" select="concat('&lt;value type=&quot;string&quot;&gt;&lt;![CDATA[',$theValue,']]&gt;&lt;/value&gt;')"/>
		<xsl:call-template name="parseNextToken">
			<xsl:with-param name="operandStack" select="$operandStack"/>
			<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring-after(substring($remaining,2),'&quot;')"/></xsl:call-template></xsl:with-param>
		</xsl:call-template>
	</xsl:when>
	</xsl:choose>
</xsl:when>

<xsl:when test="$operandChar = ','">
	<xsl:variable name="nextOperandStack"><xsl:choose><xsl:when test="substring($operandStack,1,1) = '['"><xsl:value-of select="$operandStack"/></xsl:when>
	                                                  <xsl:otherwise><xsl:value-of select="concat(',',$operandStack)"/></xsl:otherwise>
	                                      </xsl:choose></xsl:variable>
	<xsl:call-template name="parseNextToken">
		<xsl:with-param name="operandStack" select="$nextOperandStack"/>
		<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($remaining,2)"/></xsl:call-template></xsl:with-param>
	</xsl:call-template>
</xsl:when>

<xsl:when test="contains('0123456789.-',$operandChar)">
	<xsl:variable name="numberString"><xsl:call-template name="getNumberString"><xsl:with-param name="theString" select="$remaining"/></xsl:call-template></xsl:variable>
	<xsl:variable name="afterNumberString"><xsl:call-template name="getAfterNumberString"><xsl:with-param name="theString" select="$remaining"/></xsl:call-template></xsl:variable>
	<xsl:choose>
	<xsl:when test="substring($operandStack,1,1) = '['">  <!-- value in an array -->
		<xsl:variable name="remainingAfterValue"><xsl:choose><xsl:when test="substring($afterNumberString,1,1) = ','"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($afterNumberString,2)"/></xsl:call-template></xsl:when>
		                                                     <xsl:otherwise><xsl:value-of select="$afterNumberString"/></xsl:otherwise>
		                                         </xsl:choose>
	    </xsl:variable> <!-- $remainingAfterValue is used to swallow the comma in a series of values within an array -->
		<xsl:value-of disable-output-escaping="yes" select="concat('&lt;arrayItem type=&quot;number&quot;&gt;',$numberString,'&lt;/arrayItem&gt;')"/>
		<xsl:call-template name="parseNextToken">
			<xsl:with-param name="operandStack" select="$operandStack"/> <!-- keep the bracket as the operator -->
			<xsl:with-param name="remaining" select="$remainingAfterValue"/>
		</xsl:call-template>
	</xsl:when>
	<xsl:when test="substring($operandStack,1,1) = ':'">  <!-- elementary value  -->
		<xsl:value-of disable-output-escaping="yes" select="concat('&lt;value type=&quot;number&quot;&gt;',$numberString,'&lt;/value&gt;')"/>
		<xsl:call-template name="parseNextToken">
			<xsl:with-param name="operandStack" select="$operandStack"/>
			<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="$afterNumberString"/></xsl:call-template></xsl:with-param>
		</xsl:call-template>
	</xsl:when>
	</xsl:choose> 
</xsl:when>

<xsl:when test="substring($remaining,1,4) = 'true' or substring($remaining,1,5) = 'false' or substring($remaining,1,4) = 'null'">
<xsl:variable name="keyword"><xsl:choose><xsl:when test="substring($remaining,1,4) = 'true'">true</xsl:when>
                                         <xsl:when test="substring($remaining,1,5) = 'false'">false</xsl:when>
										 <xsl:when test="substring($remaining,1,4) = 'null'">null</xsl:when></xsl:choose></xsl:variable>
	<xsl:value-of disable-output-escaping="yes" select="concat('&lt;value type=&quot;',$keyword,'&quot;&gt;',$keyword,'&lt;/value&gt;')"/>
	<xsl:call-template name="parseNextToken">
		<xsl:with-param name="operandStack" select="$operandStack"/>
		<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($remaining,string-length($keyword)+1)"/></xsl:call-template></xsl:with-param>
	</xsl:call-template>
</xsl:when>

<xsl:otherwise>
	<xsl:value-of disable-output-escaping="yes" select="concat('&lt;parseError&gt;',substring($remaining,1,1),'&lt;/parseError&gt;')"/>
	<xsl:call-template name="parseNextToken">
		<xsl:with-param name="operandStack" select="$operandStack"/>
		<xsl:with-param name="remaining"><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="substring($remaining,2)"/></xsl:call-template></xsl:with-param>
	</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template name="stripLeadingWhitespace">
<xsl:param name="theString" select="'"/>
<xsl:choose>
<xsl:when test="string-length($theString) &gt; 0">
	<xsl:variable name="firstChar" select="substring($theString,1,1)"/>
	<xsl:variable name="remaining" select="substring($theString,2)"/>
	<xsl:choose>
	<xsl:when test="string-length(normalize-space($firstChar)) &gt; 0"><xsl:value-of select="$theString"/></xsl:when>
	<xsl:otherwise><xsl:call-template name="stripLeadingWhitespace"><xsl:with-param name="theString" select="$remaining"/></xsl:call-template></xsl:otherwise>
	</xsl:choose>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:template>

<xsl:template name="getNumberString">
<xsl:param name="theString" select="'"/>
<xsl:param name="outString" select="'"/>
<xsl:choose>
<xsl:when test="string-length($theString) &gt; 0">
	<xsl:choose>
	<xsl:when test="contains('0123456789.eE-+',substring($theString,1,1))"><xsl:call-template name="getNumberString">
	                                                                       <xsl:with-param name="theString" select="substring($theString,2)"/>
																		   <xsl:with-param name="outString" select="concat($outString,substring($theString,1,1))"/>
																		   </xsl:call-template></xsl:when>
	<xsl:otherwise><xsl:value-of select="$outString"/></xsl:otherwise>
	</xsl:choose>
</xsl:when>
<xsl:otherwise><xsl:value-of select="$outString"/></xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template name="getAfterNumberString">
<xsl:param name="theString" select="'"/>
<xsl:choose>
<xsl:when test="string-length($theString) &gt; 0">
	<xsl:choose>
	<xsl:when test="contains('0123456789.eE-+',substring($theString,1,1))"><xsl:call-template name="getAfterNumberString">
	                                                                       <xsl:with-param name="theString" select="substring($theString,2)"/>
																		   </xsl:call-template></xsl:when>
	<xsl:otherwise><xsl:value-of select="$theString"/></xsl:otherwise>
	</xsl:choose>
</xsl:when>
<xsl:otherwise></xsl:otherwise>
</xsl:choose>
</xsl:template>

</xsl:stylesheet> 

XSLT for step 2 is in next submission.

Tom Morrison
Hill Country Software

RE: Converting JSON to XML using XSLT 1.0

(OP)

CODE --> XSLT.for.Step.2

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml" encoding="utf-8"/>

<xsl:template match="/">
<root><xsl:apply-templates select="*[local-name() != 'nameNode']"/></root>
</xsl:template>

<xsl:template match="value">
<xsl:variable name="nodeName"><xsl:call-template name="createNodeName"/></xsl:variable>
<xsl:element name="{$nodeName}"><xsl:value-of select="."/></xsl:element>
</xsl:template>

<xsl:template match="arrayItem">
<xsl:variable name="candidateNodeName"><xsl:choose>
                                <xsl:when test="local-name(parent::array[1]/preceding-sibling::*[1]) = 'nameNode'"><xsl:value-of select="parent::array[1]/preceding-sibling::*[1]/@name"/></xsl:when>
                                <xsl:otherwise><xsl:value-of select="local-name(.)"/></xsl:otherwise>
                              </xsl:choose></xsl:variable>
<xsl:variable name="nodeName"><xsl:value-of select="concat(translate(substring($candidateNodeName,1,1),'0123456789','xxxxxxxxxx'),translate(substring($candidateNodeName,2),'_ ','-'),'Item')"/></xsl:variable>
<xsl:element name="{$nodeName}"><xsl:value-of select="."/></xsl:element>
</xsl:template>

<xsl:template match="object|array">
<xsl:variable name="nodeName"><xsl:call-template name="createNodeName"/></xsl:variable>
<xsl:element name="{$nodeName}"><xsl:apply-templates select="*[local-name() != 'nameNode']"/></xsl:element>
</xsl:template>

<xsl:template name="createNodeName">
<xsl:variable name="candidateNodeName"><xsl:choose>
                                          <xsl:when test="local-name(preceding-sibling::*[1]) = 'nameNode'"><xsl:value-of select="preceding-sibling::*[1]/@name"/></xsl:when>
                                          <xsl:otherwise><xsl:value-of select="local-name(.)"/></xsl:otherwise>
                                       </xsl:choose></xsl:variable>
<!-- apply any adjustments necessary to get the JSON name to a valid name for an XML node.  
     As an example the following will ensure that the name will not begin with a digit or a space,
	 and that underscore and colon are converted to hyphen. -->
<xsl:variable name="actualNodeName"><xsl:value-of select="concat(translate(substring($candidateNodeName,1,1),'0123456789 ','xxxxxxxxxx'),translate(substring($candidateNodeName,2),':_ ','--'))"/></xsl:variable>
<xsl:value-of select="$actualNodeName"/>
</xsl:template>

</xsl:stylesheet> 

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members!

Resources

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close