changeset 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
files data/jsondata.xml xslt/json-person.xsl xslt/json.xsl
diffstat 3 files changed, 142 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/data/jsondata.xml	Sun Apr 08 23:30:11 2018 +0300
+++ b/data/jsondata.xml	Mon Apr 09 06:43:46 2018 +0300
@@ -1,12 +1,14 @@
 <?xml version="1.0" encoding="utf-8"?>
 <person>
-	<firstName>Harry</firstName>
-	<lastName>Busy</lastName>
-	<age>23</age>
-	<address>
+	<firstName>Peter</firstName>
+	<firstName>Craig</firstName>
+	<lastName>Jackson</lastName>
+	<age>49</age>
+	<address order="1">
 		<street>1st avenue</street>
 	</address>
-	<address>
-		<street>2nd avenue</street>
-	</address>
+	<home>
+		<tel>123-23-12</tel>
+	</home>
+	<unemployed>false</unemployed>
 </person>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xslt/json-person.xsl	Mon Apr 09 06:43:46 2018 +0300
@@ -0,0 +1,31 @@
+<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:import href="json.xsl"/>
+	<xsl:output method="text" />
+	
+	<xsl:template match="firstName | lastName" mode="json-member-value">
+		<xsl:call-template name="write-value">
+			<xsl:with-param name="value" select="key('members',concat(generate-id(..),local-name(.)))[last()]"/>
+		</xsl:call-template>
+	</xsl:template>
+	
+	<xsl:template match="address" mode="json-member-value">
+		<xsl:call-template name="write-array"/>
+	</xsl:template>
+	
+	<xsl:template match="work | home">
+		<address>
+			<_type><xsl:value-of select="local-name(.)"/></_type>
+			<xsl:copy-of select="*"/>
+		</address>
+	</xsl:template>
+	
+	<xsl:template match="@*">
+		<xsl:element name="{local-name(.)}" >
+			<xsl:value-of select="."/>
+		</xsl:element>
+	</xsl:template>
+	
+</xsl:stylesheet>
\ No newline at end of file
--- a/xslt/json.xsl	Sun Apr 08 23:30:11 2018 +0300
+++ b/xslt/json.xsl	Mon Apr 09 06:43:46 2018 +0300
@@ -1,33 +1,70 @@
 <?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: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="*[count(*) = 0]">
-		<xsl:apply-templates mode="json-value" />
-	</xsl:template>
-
-	<xsl:template match="*[count(*) > 0]">
-		<xsl:text>{ </xsl:text>
-		<xsl:apply-templates mode="json-object-member"/>
-		<xsl:text> }</xsl:text>
+	<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="text()"/>
-
+	<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 name="write-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-json-string">
+		<xsl:call-template name="write-string">
 			<xsl:with-param name="text" select="local-name(.)"/>
 		</xsl:call-template>
 		<xsl:text> : </xsl:text>
-		<xsl:apply-templates mode="json-value"/>
+		<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>
@@ -35,10 +72,6 @@
 	
 	<!-- handle json-value -->
 
-	<xsl:template match="*[@xsi:nil = 'true']">
-		<xsl:text>null</xsl:text>
-	</xsl:template>
-
 	<xsl:template match="text()[. = 'true']" mode="json-value">
 		<xsl:text>true</xsl:text>
 	</xsl:template>
@@ -54,19 +87,64 @@
 	</xsl:template>
 
 	<xsl:template match="text()" mode="json-value">
-		<xsl:call-template name="write-json-string">
+		<xsl:call-template name="write-string">
 			<xsl:with-param name="text" select="."/>
 		</xsl:call-template>
 	</xsl:template>
 
-	<xsl:template match="*" mode="json-value">
-		<xsl:apply-templates select="."/>
+	<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-json-string">
+	
+	<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>
\ No newline at end of file