Reputation: 111
I am able to transform JSON to XML using XSLT 3.0. When transforming to XML fields the data in subjects are missing the XML structure.
{
"student" : "john",
"class" : "Bachelors",
"subjects" : "<college><subject><subjects>maths</subjects><term>spring</term></subject></college>"
}
XSLT :
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="jsonText"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template name="init">
<xsl:apply-templates select="json-to-xml($jsonText)"/>
</xsl:template>
</xsl:stylesheet>`
Java Code :
public static void main(String[] args){
final String XSLT_PATH = "src/so/test1/json2xml.xsl";
final String JSON = ""{\n" +" \"student\": \"john\",\n" +
" \"class\": \"Bachelors\"\n" +
" \"subjects\": \"<college><subject><subjects>maths</subjects><term>spring</term></subject></college>"\n"
"}";
OutputStream outputStream = System.out;
Processor processor = new Processor(false);
Serializer serializer = processor.newSerializer();
serializer.setOutputStream(outputStream);
XsltCompiler compiler = processor.newXsltCompiler();
XsltExecutable executable = compiler.compile(new StreamSource(new File(XSLT_PATH)));
XsltTransformer transformer = executable.load();
transformer.setInitialTemplate(new QName("init"));
transformer.setParameter(new QName("jsonText"), new
XdmAtomicValue(JSON));
transformer.setDestination(serializer);
transformer.transform();
}
Error:
Error at char 12 in xsl:apply-templates/@select on line 8 column 58 of json2xml.xsl:
FOJS0001: Invalid JSON input: Unescaped control character (xd)
Exception in thread "main" net.sf.saxon.s9api.SaxonApiException: Invalid JSON input: Unescaped control character (xd)
at net.sf.saxon.s9api.XsltTransformer.transform(XsltTransformer.java:599)
at com.xmltojson.sampleclass.SimpleJaxp.main(SimpleJaxp.java:49)
Caused by: net.sf.saxon.trans.XPathException: Invalid JSON input: Unescaped control character (xd)
Upvotes: 1
Views: 3314
Reputation: 167716
Add a template
<xsl:template match="string[@key = 'subjects']" xpath-default-namespace="http://www.w3.org/2005/xpath-functions">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:sequence select="parse-xml(.)/node()"/>
</xsl:copy>
</xsl:template>
to make sure the string data is parsed to XML.
Note that using XSLT 3.0 you can use <xsl:mode on-no-match="shallow-copy"/>
instead of having to spell out the identity transformation.
A quick example is
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="jsonText"><![CDATA[{
"student" : "john",
"class" : "Bachelors",
"subjects" : "<college><subject><subjects>maths</subjects><term>spring</term></subject></college>"
}]]></xsl:param>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template name="init">
<xsl:apply-templates select="json-to-xml($jsonText)"/>
</xsl:template>
<xsl:template match="string[@key = 'subjects']" xpath-default-namespace="http://www.w3.org/2005/xpath-functions">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:sequence select="parse-xml(.)/node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
which (when run with Saxon 9.8.0.3 HE with it:init
) outputs
<?xml version="1.0" encoding="UTF-8"?>
<map xmlns="http://www.w3.org/2005/xpath-functions">
<string key="student">john</string>
<string key="class">Bachelors</string>
<string key="subjects">
<college xmlns="">
<subject>
<subjects>maths</subjects>
<term>spring</term>
</subject>
</college>
</string>
</map>
Here is a complete Java program based on your code snippets posted in various edits:
import java.io.File;
import java.io.OutputStream;
import javax.xml.transform.stream.StreamSource;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.Serializer;
import net.sf.saxon.s9api.XdmAtomicValue;
import net.sf.saxon.s9api.XsltCompiler;
import net.sf.saxon.s9api.XsltExecutable;
import net.sf.saxon.s9api.XsltTransformer;
public class Saxon98HETest1 {
public static void main(String[] args) throws SaxonApiException {
final String XSLT_PATH = "sheet1.xsl";
String JSON = "{\n" +
" \"student\" : \"john\",\n" +
" \"class\" : \"Bachelors\",\n" +
" \"subjects\" : \"<college><subject><subjects>maths</subjects><term>spring</term></subject></college>\"\n" +
"}";
testJsonToXml(XSLT_PATH, JSON);
System.out.println();
JSON = "{\n" +
" \"color\": \"red\",\n" +
" \"value\": \"#f00\"\n" +
"}";
testJsonToXml(XSLT_PATH, JSON);
System.out.println();
}
static void testJsonToXml(String xsl, String json) throws SaxonApiException {
OutputStream outputStream = System.out;
Processor processor = new Processor(false);
Serializer serializer = processor.newSerializer();
serializer.setOutputStream(outputStream);
XsltCompiler compiler = processor.newXsltCompiler();
XsltExecutable executable = compiler.compile(new StreamSource(new File(xsl)));
XsltTransformer transformer = executable.load();
transformer.setInitialTemplate(new QName("init"));
transformer.setParameter(new QName("jsonText"), new XdmAtomicValue(json));
transformer.setDestination(serializer);
transformer.transform();
}
}
When compiled and run against Saxon 9.8.0.3 HE I get the output
<?xml version="1.0" encoding="UTF-8"?>
<map xmlns="http://www.w3.org/2005/xpath-functions">
<string key="student">john</string>
<string key="class">Bachelors</string>
<string key="subjects">
<college xmlns="">
<subject>
<subjects>maths</subjects>
<term>spring</term>
</subject>
</college>
</string>
</map>
<?xml version="1.0" encoding="UTF-8"?>
<map xmlns="http://www.w3.org/2005/xpath-functions">
<string key="color">red</string>
<string key="value">#f00</string>
</map>
and no errors. The stylesheet is as shown above, without the preset param content:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="jsonText"></xsl:param>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template name="init">
<xsl:apply-templates select="json-to-xml($jsonText)"/>
</xsl:template>
<xsl:template match="string[@key = 'subjects']" xpath-default-namespace="http://www.w3.org/2005/xpath-functions">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:sequence select="parse-xml(.)/node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 2