Re: [xsl] json to json transformation

Subject: Re: [xsl] json to json transformation
From: "Martin Honnen martin.honnen@xxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 15 Mar 2019 10:49:21 -0000
On 15.03.2019 11:42, Mukul Gandhi gandhi.mukul@xxxxxxxxx wrote:
Hi all,
B B XPath 3.1 has functions json-to-xml() and xml-to-json(). I thought of using these two functions in a XSLT 3.0 stylesheet, to do json to json transformations. Below is an example of this,


Input JSON fileB person.txt:

{
 B  B "id" : 105,
 B  B "medals" : [1, 2, 3],
 B  B "fName" : "Mukul",
 B  B "lName" : "Gandhi",
 B  B "address" : {
 B  B  B  "street1" : "xyz",
 B  B  B  "street2" : "maddison avenue",
 B  B  B  "country" : "C1"
 B  B  }
}

I wish to transform above JSON document, into another JSON document which should look like following,

{
 B  B "id" : 105,
 B  B "medals" : [1, 2, 3],
 B  B "name" : "Mukul Gandhi",
 B  B "address" : {
 B  B  B  "street1" : "xyz",
 B  B  B  "street2" : "maddison avenue",
 B  B  B  "country" : "C1"
 B  B  }
}

Everything in second JSON document is same as the first one, except that "fName" and "lName" fields have been merged into one "name" field. Following is a XSLT stylesheet I've written for the mentioned requirements,

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
B B B B B B B B B B B B B xmlns:xs="http://www.w3.org/2001/XMLSchema";
B B B B B B B B B B B B B xmlns:fn="http://www.w3.org/2005/xpath-functions";
B B B B B B B B B B B B B exclude-result-prefixes="xs fn"
B B B B B B B B B B B B B version="3.0">
B B <xsl:variable name="inpJson" select="unparsed-text('person.txt')" as="xs:string"/>
B B <xsl:output method="text" />
B B <xsl:template match="/">
B B B B <xsl:variable name="inpXml" select="json-to-xml($inpJson)"/>
B B B B <xsl:variable name="intermediate">
B B B B B <xsl:apply-templates select="$inpXml/fn:map" mode="M0"/>
B B B B </xsl:variable>
B B B B <xsl:copy-of select="xml-to-json($intermediate, map{'indent': true()})"/>
B B </xsl:template>
B B <xsl:template match="node() | @*" mode="M0">
B B B B <xsl:copy>
B B B B B B <xsl:apply-templates select="node() | @*" mode="M0"/>
B B B B </xsl:copy>
B B </xsl:template>
B B <xsl:template match="fn:string[@key = 'fName']" mode="M0">
B B B B <fn:string key="name"><xsl:value-of select="concat(., ' ', following-sibling::fn:string[1])"/></fn:string>
B B </xsl:template>
B B <xsl:template match="fn:string[@key = 'lName']" mode="M0"/>
</xsl:stylesheet>


The above mentioned stylesheet, produces the wanted results.

Just thought of sharing these facts with members here, for any comments, suggestions.

Given XSLT 3, you can simply declare


<xsl:mode name="M0" on-no-match="shallow-copy"/>

instead of the identity transformation template you have set up for that mode.

And you can shorten the code using other XSLT/XPath 3 constructs like using the string concatenation operator

. || ' ' || following-sibling::fn:string[1])

instead of concat.

Current Thread