Mercurial > pub > ModelGenerator
diff xslt/json.xsl @ 13:197a850b1f6f default tip
working version of xml2json transformation
author | cin |
---|---|
date | Mon, 09 Apr 2018 16:27:26 +0300 |
parents | 191b81b2052b |
children |
line wrap: on
line diff
--- a/xslt/json.xsl Mon Apr 09 06:43:46 2018 +0300 +++ b/xslt/json.xsl Mon Apr 09 16:27:26 2018 +0300 @@ -5,52 +5,38 @@ xmlns:exsl="http://exslt.org/common"> <xsl:output method="text" /> - <xsl:key name="members" match="*" use="concat(generate-id(..),local-name(.))"/> - <xsl:template match="/"> - <xsl:variable name="doc"> - <xsl:apply-templates/> - </xsl:variable> - <xsl:apply-templates select="exsl:node-set($doc)" mode="json-value" /> + <xsl:apply-templates mode="json-value" /> </xsl:template> - <xsl:template match="*"> - <xsl:copy> - <xsl:apply-templates select="@*"/> - <xsl:apply-templates/> - </xsl:copy> - </xsl:template> - - <xsl:template match="@*"> - <xsl:copy/> - </xsl:template> <!-- handle json-object --> - <xsl:template match="*" mode="json-object-members"> - <xsl:apply-templates select="." mode="json-object-members-internal"/> - </xsl:template> - - <xsl:template match="*" mode="json-object-members-internal"> - <xsl:variable name="oid" select="generate-id(.)"/> - <xsl:variable name="grouped" select="*[generate-id(.) = generate-id(key('members',concat($oid,local-name(.))))]"/> - <xsl:apply-templates select="$grouped" mode="json-object-member"/> + <xsl:template match="*" mode="json-object"> + <xsl:call-template name="write-members"/> </xsl:template> - <xsl:template match="*" mode="json-object-member"> + <xsl:template match="*|@*" mode="json-member"> + <xsl:param name="values" select="."/> <xsl:call-template name="write-string"> - <xsl:with-param name="text" select="local-name(.)"/> + <xsl:with-param name="text"><xsl:apply-templates select="." mode="json-member-name"/></xsl:with-param> </xsl:call-template> <xsl:text> : </xsl:text> - <xsl:apply-templates select="." mode="json-member-value"/> - <xsl:if test="position() != last()"> - <xsl:text>, </xsl:text> - </xsl:if> + <xsl:apply-templates select="." mode="json-member-value"> + <xsl:with-param name="values" select="$values"/> + </xsl:apply-templates> </xsl:template> - <xsl:template match="*" mode="json-member-value"> - <xsl:variable name="oid" select="generate-id(..)"/> - <xsl:variable name="values" select="key('members',concat($oid,local-name(.)))"/> + <xsl:template match="*" mode="json-member-name"> + <xsl:value-of select="local-name(.)"/> + </xsl:template> + + <xsl:template match="@*" mode="json-member-name"> + <xsl:value-of select="concat('_',local-name(.))"/> + </xsl:template> + + <xsl:template match="*|@*" mode="json-member-value"> + <xsl:param name="values" select="."/> <xsl:choose> <xsl:when test="count($values) > 1"> <xsl:call-template name="write-array"> @@ -63,7 +49,7 @@ </xsl:choose> </xsl:template> - <xsl:template match="*" mode="json-array-item"> + <xsl:template match="*|@*" mode="json-array-item"> <xsl:apply-templates select="." mode="json-value"/> <xsl:if test="position() != last()"> <xsl:text>, </xsl:text> @@ -72,21 +58,21 @@ <!-- handle json-value --> - <xsl:template match="text()[. = 'true']" mode="json-value"> + <xsl:template match="text()[. = 'true'] | @*[. = 'true']" mode="json-value"> <xsl:text>true</xsl:text> </xsl:template> - <xsl:template match="text()[. = 'false']" + <xsl:template match="text()[. = 'false'] | @*[. = 'false']" mode="json-value"> <xsl:text>false</xsl:text> </xsl:template> - <xsl:template match="text()[string(number(.)) != 'NaN']" + <xsl:template match="text()[string(number(.)) != 'NaN'] | @*[string(number(.)) != 'NaN']" mode="json-value"> <xsl:value-of select="number(.)" /> </xsl:template> - <xsl:template match="text()" mode="json-value"> + <xsl:template match="text()|@*" mode="json-value"> <xsl:call-template name="write-string"> <xsl:with-param name="text" select="."/> </xsl:call-template> @@ -104,47 +90,163 @@ <xsl:template name="write-value"> <xsl:param name="value" select="."/> - <xsl:apply-templates select="exsl:node-set($value)" mode="json-value"/> + <xsl:apply-templates select="$value" mode="json-value"/> </xsl:template> - <xsl:template name="write-named-value"> + <xsl:template name="write-member"> + <xsl:param name="name"/> + <xsl:param name="value"/> + <xsl:call-template name="write-string"> + <xsl:with-param name="text" select="$name"/> + </xsl:call-template> + <xsl:text> : </xsl:text> + <xsl:apply-templates select="$value" mode="json-value"/> + </xsl:template> + + <xsl:template name="write-member-string"> <xsl:param name="name"/> <xsl:param name="value"/> <xsl:call-template name="write-string"> <xsl:with-param name="text" select="$name"/> </xsl:call-template> <xsl:text> : </xsl:text> - <xsl:apply-templates select="exsl:node-set($value)"/> + <xsl:call-template name="write-string"> + <xsl:with-param name="text" select="$value"/> + </xsl:call-template> + </xsl:template> + + <xsl:template name="write-member-array"> + <xsl:param name="name"/> + <xsl:param name="values"/> + <xsl:call-template name="write-string"> + <xsl:with-param name="text" select="$name"/> + </xsl:call-template> + <xsl:text> : </xsl:text> + <xsl:call-template name="write-array"> + <xsl:with-param name="values" select="$values"/> + </xsl:call-template> + </xsl:template> + + <xsl:template name="write-separator"> + <xsl:text>, </xsl:text> </xsl:template> <!-- specialized template traits --> <xsl:template name="write-string"> <xsl:param name="text"/> - <xsl:value-of select="concat('"', $text,'"')" /> + <xsl:text>"</xsl:text> + <xsl:call-template name="escape-bs-string"> + <xsl:with-param name="s" select="$text"/> + </xsl:call-template> + <xsl:text>"</xsl:text> </xsl:template> <xsl:template name="write-object"> <xsl:param name="value" select="."/> <xsl:text>{ </xsl:text> - <xsl:apply-templates select="$value" mode="json-object-members"/> + <xsl:apply-templates select="$value" mode="json-object"/> <xsl:text> }</xsl:text> </xsl:template> <xsl:template name="write-array"> - <xsl:param name="oid" select="generate-id(..)"/> - <xsl:param name="values" select="key('members',concat($oid,local-name(.)))"/> + <xsl:param name="values"/> <xsl:text>[ </xsl:text> <xsl:apply-templates select="$values" mode="json-array-item"/> <xsl:text> ]</xsl:text> </xsl:template> - <xsl:template name="write-object-members"> - <xsl:param name="object" select="."/> - <xsl:for-each select="exsl:node-set($object)"> - <xsl:apply-templates select="." mode="json-object-members-internal"/> + <xsl:template name="write-members"> + <xsl:param name="members" select="*"/> + + <xsl:for-each select="$members"> + <xsl:variable name="current" select="."/> + <xsl:variable name="values" select="$members[local-name(.) = local-name($current)]"/> + <xsl:if test="generate-id($current) = generate-id($values)"> + <xsl:if test="position()>1"> + <xsl:call-template name="write-separator"/> + </xsl:if> + <xsl:apply-templates select="$current" mode="json-member"> + <xsl:with-param name="values" select="$values"/> + </xsl:apply-templates> + </xsl:if> </xsl:for-each> </xsl:template> + + <!-- escape string --> + <!-- + Copyright (c) 2006,2008 Doeke Zanstra + All rights reserved. + https://github.com/doekman/xml2json-xslt/blob/master/xml2json.xslt + --> + <!-- Escape the backslash (\) before everything else. --> + <xsl:template name="escape-bs-string"> + <xsl:param name="s"/> + <xsl:choose> + <xsl:when test="contains($s,'\')"> + <xsl:call-template name="escape-quot-string"> + <xsl:with-param name="s" select="concat(substring-before($s,'\'),'\\')"/> + </xsl:call-template> + <xsl:call-template name="escape-bs-string"> + <xsl:with-param name="s" select="substring-after($s,'\')"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="escape-quot-string"> + <xsl:with-param name="s" select="$s"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- Escape the double quote ("). --> + <xsl:template name="escape-quot-string"> + <xsl:param name="s"/> + <xsl:choose> + <xsl:when test="contains($s,'"')"> + <xsl:call-template name="encode-string"> + <xsl:with-param name="s" select="concat(substring-before($s,'"'),'\"')"/> + </xsl:call-template> + <xsl:call-template name="escape-quot-string"> + <xsl:with-param name="s" select="substring-after($s,'"')"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="encode-string"> + <xsl:with-param name="s" select="$s"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- Replace tab, line feed and/or carriage return by its matching escape code. Can't escape backslash + or double quote here, because they don't replace characters (� becomes \t), but they prefix + characters (\ becomes \\). Besides, backslash should be seperate anyway, because it should be + processed first. This function can't do that. --> + <xsl:template name="encode-string"> + <xsl:param name="s"/> + <xsl:choose> + <!-- tab --> + <xsl:when test="contains($s,'	')"> + <xsl:call-template name="encode-string"> + <xsl:with-param name="s" select="concat(substring-before($s,'	'),'\t',substring-after($s,'	'))"/> + </xsl:call-template> + </xsl:when> + <!-- line feed --> + <xsl:when test="contains($s,'
')"> + <xsl:call-template name="encode-string"> + <xsl:with-param name="s" select="concat(substring-before($s,'
'),'\n',substring-after($s,'
'))"/> + </xsl:call-template> + </xsl:when> + <!-- carriage return --> + <xsl:when test="contains($s,'
')"> + <xsl:call-template name="encode-string"> + <xsl:with-param name="s" select="concat(substring-before($s,'
'),'\r',substring-after($s,'
'))"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise><xsl:value-of select="$s"/></xsl:otherwise> + </xsl:choose> + </xsl:template> </xsl:stylesheet> \ No newline at end of file