如何使用xslt将json转换为xml

时间:2012-10-22 08:08:01

标签: xslt xslt-1.0

如何将JSON转换为XML?

考虑:

<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>

转换后,文件如下:

<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>

8 个答案:

答案 0 :(得分:7)

我在JSON解析方面的工作并没有涵盖完整的JSON语法。

将任何JSON文档“翻译”到XML文档的任务没有解决方案。有JSON构造,如果没有定义其他约定并引入其他元素,则无法转换为XML - 因此最终的XML结构不是原始JSON对象的真实和自然表示。

在XSLT 3.0中,有一个函数可以解析任何JSON对象 - parse-json() - 到map - XSLT 3.0中引入的新数据类型。在这里阅读: http://www.w3.org/TR/xslt-30/#json

答案 1 :(得分:5)

实际上,并不难。接近它的方法是检查jason的语法,并查看每个生产,就像​​它是一个模板。当我考虑OP可能忘记谷歌预先存在的解决方案时,我正准备写一个解决方案。我搜索了一下,看到了....

更新

这是一个JSon to XML转换器。但它只适用于json的一个子集。希望该子集足够广泛以满足您的特定需求。特别是限制是:

  1. 支持的唯一简单类型是string。没有整数,布尔值或null。
  2. Json对象名称必须是有效的xml元素名称。
  3. 字符串值中不允许使用转义码。这意味着您无法传输包含例如“字符(不滚动您自己的编码层)”的值。
  4. 此XSLT 1.0样式表... *

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

    ...应用于此输入(从提供的OP中修改以删除无关的逗号)...

    <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>
    

    ..产量...

    <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>
    

答案 2 :(得分:2)

更新塞缪尔·墨菲(Samuel Murphy)的答案。

更新包括:

  • 支持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="'&quot;'" />
    <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>

答案 3 :(得分:1)

我稍微调整了Sean B. Durkin的模板,并认为我会分享。

更新包括:

  • 支持号码
  • 支持布尔值
  • 修复以逗号分隔的对象数组元素(根据JSON规范)

非更新更改:

  • 数组元素以自己的XML元素显示,元素名称为对象键,后缀为_element

仍不支持:

  • 字符串中的转义字符(引号)

这是模板:

<?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>

使用此(调整后的)输入:

<?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>

我得到了这个输出:

<?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>

答案 4 :(得分:1)

该问题已标记为XSLT 1.0,因此我不知道此答案是否有助于解决原始问题。但是,如果您可以使用XSLT 3.0,则函数json-to-xml可以完全满足您的需求。

https://www.w3.org/TR/xslt-30/#func-json-to-xml

答案 5 :(得分:0)

除了Dimitre的XSLT解析框架外,还有Gunther Rademacher的Rex解析器生成器,它还包含JSON作为其示例语法之一:

http://www.bottlecaps.de/rex/

答案 6 :(得分:0)

试试这个lib:

https://github.com/bramstein/xsltjson

看起来非常好。

它是一个2.0 XSLT解决方案,虽然他也指向1.0版本。

答案 7 :(得分:-1)

XSLT有许多优点和一些重大缺点。文本处理至少是版本1.0的弱点 虽然在技术上可以使用XSLT 1.0处理该文本,但我想不出任何情况,这将是一个非常好的主意,并且它不会是一个非常脆弱的转换。您必须生成的代码非常笨拙。

您是否没有其他语言可供处理?