view xslt/json.xsl @ 12:191b81b2052b

first version of the xslt transform from xml to json
author cin
date Mon, 09 Apr 2018 06:43:46 +0300
parents 14162f9133a1
children 197a850b1f6f
line wrap: on
line source

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	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: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>
	
	<xsl:template match="*" mode="json-object-member">
		<xsl:call-template name="write-string">
			<xsl:with-param name="text" select="local-name(.)"/>
		</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: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:choose>
			<xsl:when test="count($values) > 1">
				<xsl:call-template name="write-array">
					<xsl:with-param name="values" select="$values"/>
				</xsl:call-template>
			</xsl:when>
			<xsl:otherwise>
				<xsl:apply-templates select="$values" mode="json-value"/>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	
	<xsl:template match="*" mode="json-array-item">
		<xsl:apply-templates select="." mode="json-value"/>
		<xsl:if test="position() != last()">
			<xsl:text>, </xsl:text>
		</xsl:if>
	</xsl:template>
	
	<!-- handle json-value -->

	<xsl:template match="text()[. = 'true']" mode="json-value">
		<xsl:text>true</xsl:text>
	</xsl:template>

	<xsl:template match="text()[. = 'false']"
		mode="json-value">
		<xsl:text>false</xsl:text>
	</xsl:template>

	<xsl:template match="text()[string(number(.)) != 'NaN']"
		mode="json-value">
		<xsl:value-of select="number(.)" />
	</xsl:template>

	<xsl:template match="text()" mode="json-value">
		<xsl:call-template name="write-string">
			<xsl:with-param name="text" select="."/>
		</xsl:call-template>
	</xsl:template>

	<xsl:template match="*[boolean(* | @*) or not(text())]" mode="json-value">
		<xsl:call-template name="write-object"/>
	</xsl:template>
	
	<xsl:template match="*[@xsi:nil = 'true']" mode="json-value">
		<xsl:text>null</xsl:text>
	</xsl:template>
	
	<!-- template traits -->
	
	<xsl:template name="write-value">
		<xsl:param name="value" select="."/>
		<xsl:apply-templates select="exsl:node-set($value)" mode="json-value"/>
	</xsl:template>
	
	<xsl:template name="write-named-value">
		<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:template>
	
	<!-- specialized template traits -->
	
	<xsl:template name="write-string">
		<xsl:param name="text"/>
		<xsl:value-of select="concat('&quot;', $text,'&quot;')" />
	</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: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: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:for-each>
	</xsl:template>

</xsl:stylesheet>