As already mentioned at the comment, XSLT is generally the wrong tool to produce JSON. But if you already checked the link provided and still want to test if it works for your requirements or other reasons, following XSLT generates a text file which is, for your example input XML, valid JSON format:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" doctype-public="XSLT-compat"
omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:template match="table">
<xsl:text>{ "table" : {</xsl:text>
<xsl:apply-templates/>
<xsl:text>}}</xsl:text>
</xsl:template>
<xsl:template match="*[starts-with(local-name(),'source') and .//data]">
<xsl:text>"</xsl:text>
<xsl:value-of select="local-name()"/>
<xsl:text>" :</xsl:text>
<xsl:text>{</xsl:text>
<xsl:apply-templates select="@*|node()"/>
<xsl:text>}</xsl:text>
<xsl:if test="following-sibling::*[starts-with(local-name(),'source')
and .//data]">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:template>
<xsl:template match="data">
<xsl:text>"</xsl:text>
<xsl:value-of select="@name"/>
<xsl:text>" : "</xsl:text>
<xsl:value-of select="."/>
<xsl:text>"</xsl:text>
<xsl:if test="following-sibling::data">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:template>
<xsl:template match="*[starts-with(local-name(),'source')
and not(.//data)]"/>
</xsl:transform>
when applied to your input XML produces the following output:
{ "table" : {
"source1" :{
"text1" : "20431",
"text2" : "collins",
"text3" : "20141231>",
"text4" : "regard"
},
"source2" :{
"note1" : "C",
"note2" : "A",
"note3" : "22356",
"note4" : "465506",
"note5" : "434562491057912",
"note6" : "milk",
"note7" : "dfRTA"
}
}}
Though not totally clear from the input, you mentioned as comment that all data elements need to be converted, so I excluded every parent element which name starts with source
and has no children nodes with the name data
(source3
in your example) and applied an empty template at the end to remove it from the ouput.
Note that for performance the expressions checking if source
nodes contains any data
nodes could be improved, depending on the input - e.g. in case it's known that sources containing data
have this always wrapped in ptr
, it's better to adjust match patterns like <xsl:template match="*[starts-with(local-name(),'source') and .//data]">
to <xsl:template match="*[starts-with(local-name(),'source') and ptr]">
( or to ptr/data
in case empty ptr
elements could occur).
In case you want to remove unnecessary space from the output, you can add <xsl:strip-space elements="*"/>
below the <xsl:output>
to have the resulting text/"JSON" in one line.