使用 XSLT1.0 将 JSON 转换为 XML

问题描述 投票:0回答:1

我想使用XSLT1.0将属于XML一部分的JSON转换为XML结构(原因是我们的应用程序仅支持XSLT1.0版本)。 有人可以检查一下并让我知道吗?谢谢你

XML(with JSON): 在下面的例子中,code标签下有要转换的JSON。

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

预期输出:

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

尝试使用我在博客之一中找到的以下 XSLT。

    <?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>
json xml xslt xslt-1.0
1个回答
0
投票

这里有一个你可以作为起点的东西(实际上,它已经几乎完成了,你只需要填写一些空白)。这遵循我在对您的问题的评论中所说的:它是专门针对您的 JSON 结构量身定制的。

XSLT 1.0

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

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="code">
    <xsl:copy>
        <!-- extract values from  elements at the top level -->
        <desc>
            <xsl:value-of select="substring-before(substring-after(., '&quot;desc&quot;:&quot;'), '&quot;')" />
        </desc>
        <city>
            <xsl:value-of select="substring-before(substring-after(., '&quot;city&quot;:&quot;'), '&quot;')" />
        </city>
        <!-- ... continue for other elements at the top level -->
        
        <!-- process the array -->
        <store>
             <xsl:call-template name="process-array">
                <xsl:with-param name="array" select="substring-before(substring-after(., '['), ']')" />
             </xsl:call-template>   
        </store>
    </xsl:copy>
</xsl:template> 

<xsl:template name="process-array">
    <xsl:param name="array"/>
    <xsl:param name="delimiter" select="'},{'"/>
    <xsl:variable name="object" select="substring-before(concat($array, ',{'), $delimiter)" />
    <xsl:if test="$object">
        <element>
            <quantity>
                <xsl:value-of select="substring-before(substring-after($object, '&quot;quantity&quot;:'), ',')" />
            </quantity>
            <amount>
                <xsl:value-of select="substring-after($object, '&quot;amount&quot;:')" />
            </amount>
        </element>
    </xsl:if>
    <xsl:if test="contains($array, $delimiter)">
        <!-- recursive call -->
        <xsl:call-template name="process-array">
            <xsl:with-param name="array" select="substring-after($array, $delimiter)"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

应用于您的输入示例,这将返回:

结果

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <root>
      <order>131as</order>
      <type>se134</type>
      <num>15643</num>
      <curr>USD</curr>
      <code>
         <desc>Testing123</desc>
         <city>Dubai</city>
         <store>
            <element>
               <quantity>1</quantity>
               <amount>2.00</amount>
            </element>
            <element>
               <quantity>100</quantity>
               <amount>-8.33</amount>
            </element>
            <element>
               <quantity>300</quantity>
               <amount>-15.00</amount>
            </element>
         </store>
      </code>
   </root>
   <root>
      <order>231as</order>
      <type>se134</type>
      <num>15643</num>
      <curr>AED</curr>
      <code>
         <desc>testdesc</desc>
         <city>SHarjah</city>
         <store>
            <element>
               <quantity>1</quantity>
               <amount>10.00</amount>
            </element>
            <element>
               <quantity>100</quantity>
               <amount>98.33</amount>
            </element>
            <element>
               <quantity>300</quantity>
               <amount>-1.00</amount>
            </element>
         </store>
      </code>
   </root>
   <root>
      <order>331as</order>
      <type>se134</type>
      <num>15643</num>
      <curr>SAR</curr>
      <code>
         <desc/>
         <city/>
         <store/>
      </code>
   </root>
   <root>
      <order>431as</order>
      <type>se134</type>
      <num>15643</num>
      <curr>USD</curr>
      <code>
         <desc/>
         <city/>
         <store/>
      </code>
   </root>
   <root>
      <order>531as</order>
      <type>Tse134</type>
      <num>15643</num>
      <curr>AED</curr>
      <code>
         <desc>testdesc</desc>
         <city>Abudabhi</city>
         <store>
            <element>
               <quantity>71</quantity>
               <amount>10.00</amount>
            </element>
            <element>
               <quantity>100</quantity>
               <amount>95.33</amount>
            </element>
            <element>
               <quantity>300</quantity>
               <amount>-8.00</amount>
            </element>
         </store>
      </code>
   </root>
</root>
© www.soinside.com 2019 - 2024. All rights reserved.