1 <?xml version="1.0" encoding="utf-8"?>
2 <!-- Downloaded on 12/6/2012 from http://www.gerixsoft.com/blog/xslt/json2xml -->
4 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
6 <xsl:template match="json">
8 <xsl:copy-of select="@*"/>
9 <xsl:call-template name="json2xml">
10 <xsl:with-param name="text" select="."/>
15 <xsl:template name="json2xml">
16 <xsl:param name="text"/>
17 <xsl:variable name="mode0">
18 <xsl:variable name="regexps" select="'//(.*?)\n', '/\*(.*?)\*/', '(''|")(([^\\]|\\[\\"''/btnvfr])*?)\3', '(-?\d+(\.\d+([eE][+-]?\d+)?|[eE][+-]?\d+))', '(-?[1-9]\d*)', '(-?0[0-7]+)', '(-?0x[0-9a-fA-F]+)', '([:,\{\}\[\]])', '(true|false)', '(null)'"/>
19 <xsl:analyze-string select="$text" regex="{string-join($regexps,'|')}" flags="s">
20 <xsl:matching-substring>
22 <!-- single line comment -->
23 <xsl:when test="regex-group(1)">
25 <xsl:value-of select="regex-group(1)"/>
27 <xsl:text> </xsl:text>
29 <!-- multi line comment -->
30 <xsl:when test="regex-group(2)">
32 <xsl:value-of select="regex-group(2)"/>
36 <xsl:when test="regex-group(3)">
38 <xsl:analyze-string select="regex-group(4)" regex="\\([\\"'/btnvfr])" flags="s">
39 <xsl:matching-substring>
40 <xsl:variable name="s" select="regex-group(1)"/>
42 <xsl:when test="$s=('\', '"', '''', '/')">
43 <xsl:value-of select="regex-group(1)"/>
45 <xsl:when test="$s='b'">
46 <!--xsl:text></xsl:text-->
47 <xsl:message select="'escape sequense \b is not supported by XML'"/>
48 <xsl:text>\b</xsl:text>
50 <xsl:when test="$s='t'">
51 <xsl:text>	</xsl:text>
53 <xsl:when test="$s='n'">
54 <xsl:text> </xsl:text>
56 <xsl:when test="$s='v'">
57 <!--xsl:text></xsl:text-->
58 <xsl:message select="'escape sequence \v is not supported by XML'"/>
59 <xsl:text>\v</xsl:text>
61 <xsl:when test="$s='f'">
62 <!--xsl:text></xsl:text-->
63 <xsl:message select="'escape sequence \f is not supported by XML'"/>
64 <xsl:text>\f</xsl:text>
66 <xsl:when test="$s='r'">
67 <xsl:text> </xsl:text>
70 <xsl:message terminate="yes" select="'internal error'"/>
73 </xsl:matching-substring>
74 <xsl:non-matching-substring>
75 <xsl:value-of select="."/>
76 </xsl:non-matching-substring>
81 <xsl:when test="regex-group(6)">
83 <xsl:value-of select="regex-group(6)"/>
87 <xsl:when test="regex-group(9)">
89 <xsl:value-of select="regex-group(9)"/>
93 <xsl:when test="regex-group(10)">
95 <xsl:value-of xmlns:Integer="java:java.lang.Integer" select="Integer:parseInt(regex-group(10), 8)"/>
99 <xsl:when test="regex-group(11)">
101 <xsl:value-of xmlns:Integer="java:java.lang.Integer" select="Integer:parseInt(replace(regex-group(11), '0x', ''), 16)"/>
105 <xsl:when test="regex-group(12)">
107 <xsl:value-of select="regex-group(12)"/>
111 <xsl:when test="regex-group(13)">
113 <xsl:value-of select="regex-group(13)"/>
117 <xsl:when test="regex-group(14)">
121 <xsl:message terminate="yes" select="'internal error'"/>
124 </xsl:matching-substring>
125 <xsl:non-matching-substring>
126 <xsl:if test="normalize-space()!=''">
127 <xsl:message select="concat('unknown token: ', .)"/>
128 <xsl:value-of select="."/>
130 </xsl:non-matching-substring>
131 </xsl:analyze-string>
133 <xsl:variable name="mode1">
134 <xsl:apply-templates mode="json2xml1" select="$mode0/node()[1]"/>
136 <xsl:variable name="mode2">
137 <xsl:apply-templates mode="json2xml2" select="$mode1"/>
139 <xsl:variable name="mode3">
140 <xsl:apply-templates mode="json2xml3" select="$mode2"/>
142 <xsl:copy-of select="$mode3"/> <!-- change $mode3 to $mode[0-2] for easy debug -->
145 <!-- json2xml1 mode: group content between {} and [] into object and array elements -->
147 <xsl:template mode="json2xml1" match="node()" priority="-9">
148 <xsl:copy-of select="."/>
149 <xsl:apply-templates mode="json2xml1" select="following-sibling::node()[1]"/>
152 <xsl:template mode="json2xml1" match="symbol[.=('}',']')]"/>
154 <xsl:template mode="json2xml1" match="symbol[.=('{','[')]">
155 <xsl:element name="{if (.='{') then 'object' else 'array'}">
156 <xsl:apply-templates mode="json2xml1" select="following-sibling::node()[1]"/>
158 <xsl:variable name="level" select="count(preceding-sibling::symbol[.=('{','[')])-count(preceding-sibling::symbol[.=('}',']')])+1"/>
159 <xsl:variable name="ender"
160 select="following-sibling::symbol[.=('}',']') and count(preceding-sibling::symbol[.=('{','[')])-count(preceding-sibling::symbol[.=('}',']')])=$level][1]"/>
161 <xsl:apply-templates mode="json2xml1" select="$ender/following-sibling::node()[1]"/>
164 <!-- json2xml2 mode: group <string>:<string|integer|double|object|array> into field element -->
166 <xsl:template priority="-9" mode="json2xml2" match="@*|node()">
168 <xsl:apply-templates mode="json2xml2" select="@*|node()"/>
172 <xsl:template mode="json2xml2"
173 match="string[following-sibling::*[1]/self::symbol[.=':'] and following-sibling::*[2]/(self::string|self::integer|self::double|self::boolean|self::object|self::array|self::null)]"/>
175 <xsl:template mode="json2xml2"
176 match="symbol[.=':'][preceding-sibling::*[1]/self::string and following-sibling::*[1]/(self::string|self::integer|self::double|self::boolean|self::object|self::array|self::null)]">
177 <field name="{preceding-sibling::*[1]}">
178 <xsl:for-each select="following-sibling::*[1]">
180 <xsl:apply-templates mode="json2xml2" select="@*|node()"/>
186 <xsl:template mode="json2xml2"
187 match="*[self::string|self::integer|self::double|self::boolean|self::object|self::array|self::null][preceding-sibling::*[2]/self::string and preceding-sibling::*[1]/self::symbol[.=':']]"/>
189 <!-- json2xml3 mode: drop comma between consecutive field and object elements -->
191 <xsl:template priority="-9" mode="json2xml3" match="@*|node()">
193 <xsl:apply-templates mode="json2xml3" select="@*|node()"/>
197 <xsl:template mode="json2xml3" match="object/symbol[.=','][preceding-sibling::*[1]/self::field and following-sibling::*[1]/self::field]"/>
199 <xsl:template mode="json2xml3" match="array/symbol[.=','][preceding-sibling::*[1]/(self::string|self::integer|self::double|self::boolean|self::object|self::array|self::null) and following-sibling::*[1]/(self::string|self::integer|self::double|self::boolean|self::object|self::array|self::null)]"/>