10

如何将 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>
4

8 回答 8

9

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

而将任何 JSON 文档“翻译”为 XML 文档的任务也没有解决方案。有 JSON 结构,如果不定义额外的约定和引入额外的元素,就无法将其转换为 XML —— 所以最终的 XML 结构并不是原始 JSON 对象的真实自然表示。

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

于 2012-10-22T13:01:04.140 回答
7

实际上,这并不难。处理它的方法是检查 jason 的语法,并像查看模板一样查看每个产品。当我考虑到 OP 忘记谷歌搜索预先存在的解决方案的可能性时,我正要写一个解决方案。我搜索并瞧瞧....

更新

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

  1. 唯一支持的简单类型是字符串。没有整数、布尔值或空值。
  2. Json 对象名称必须是有效的 xml 元素名称。
  3. 字符串值内不允许有转义码。这意味着您不能传输包含例如 " 字符的值(无需滚动您自己的编码层)。

这个 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>
于 2012-10-22T11:07:12.060 回答
5

我稍微调整了 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>
于 2016-07-22T18:19:17.087 回答
2

更新塞缪尔墨菲的答案。

更新包括:

  • 支持空
<?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>
于 2020-01-30T11:23:49.260 回答
2

这个问题被标记为 XSLT 1.0,所以我不知道这个答案是否会对原始问题有所帮助。但是,如果您可以使用 XSLT 3.0,那么该函数将json-to-xml完全满足您的需求。

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

于 2017-08-09T04:01:08.897 回答
0

As well as Dimitre's XSLT parsing framework, there is also Gunther Rademacher's Rex parser generator, which also includes JSON as one of its sample grammars:

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

于 2012-10-22T11:36:41.120 回答
0

试试这个库:

https://github.com/bramstein/xsltjson

看起来很不错。

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

于 2013-06-06T10:01:07.273 回答
-1

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

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

于 2012-10-22T08:23:16.103 回答