Issue
PROBLEM
I am working on a problem where I am required to take JSON input file and convert to a XML file. I have provided an example below of what i am deaing with.
In JSON :
"playerStats": [
{ "jerseyNumber": "23", "fgPercentage": 60, "plusMinus": "plus" },
{ "jerseyNumber": "24", "fgPercentage": 40, "plusMinus": "minus" }
] }
In XML :
<BallerStats>
<BallerStat>
<Baller><BallerJersey>23</BallerJersey><Type>Jersey</Type></Baller>
<fgPercentage><Type>PERCENT</Type><Value>60</Value></fgPercentage>
</BallerStat>
<BallerStat>
<Baller><BallerJersey>23</BallerJersey><Type>Jersey</Type></Baller>
<fgPercentage><Type>PERCENT</Type><Value>60</Value></fgPercentage>
</BallerStat>
</BallerStats>
As you can see it is not a 1 to 1 ratio meaning, in JSON we represent fgPercentage as 60 but in xml we separate it by "value" and "type"
Also certain tag names are different. In JSON we call them "playerStats" and in XML we call the equivalent tag "BallerStats"
SOLUTION
Keep in mind the JSON file could have many other fields apart from playerstats like coachstats or fanstats but we only care about playerstats
The following is what I have come up with but again I could be wrong.
- Scan Json and look for "playerStats"
- If not found , Do nothing.
- If found then grab valuable information like jerseyNumber , fgPercentage, ignore plusMinus and store them in a object of a template class with these Values.
- Then use the Object to generate appropriate XML tags.
I am not sure if my approach is effective or efficient. I would love to hear suggestions and I am doing this in Java so feel free to refer to any reliable and popular libraries. I would love to see all approaches and even better if you provide code snippet.
Solution
One option is to use json-to-xml()
in XSLT 3.0.
You'll need an XSLT 3.0 processor; I used Saxon-HE 9.8 in my example below.
You can pass the JSON in as a param.
The results of json-to-xml()
will look something like this:
<map xmlns="http://www.w3.org/2005/xpath-functions">
<array key="playerStats">
<map>
<string key="jerseyNumber">23</string>
<number key="fgPercentage">60</number>
<string key="plusMinus">plus</string>
</map>
<map>
<string key="jerseyNumber">24</string>
<number key="fgPercentage">40</number>
<string key="plusMinus">minus</string>
</map>
</array>
</map>
You can process that XML to get your target XML.
Example...
Java
package so.test1;
import java.io.File;
import java.io.OutputStream;
import javax.xml.transform.stream.StreamSource;
import net.sf.saxon.s9api.XsltTransformer;
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;
/**
*
* @author dhaley
*
*/
public class SOTest1 {
public static void main(String[] args) throws SaxonApiException {
final String XSLT_PATH = "src/so/test1/test.xsl";
final String JSON = "{\"playerStats\": [\n" +
" {\"jerseyNumber\": \"23\", \"fgPercentage\": 60, \"plusMinus\": \"plus\"},\n" +
" {\"jerseyNumber\": \"24\", \"fgPercentage\": 40, \"plusMinus\": \"minus\"}\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")); //<-- SET INITIAL TEMPLATE
transformer.setParameter(new QName("json"), new XdmAtomicValue(JSON)); //<-- PASS JSON IN AS PARAM
transformer.setDestination(serializer);
transformer.transform();
}
}
XSLT 3.0 (test.xsl)
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://www.w3.org/2005/xpath-functions">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="json"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template name="init">
<!--Only process playerStats-->
<xsl:apply-templates select="json-to-xml($json)//array[@key='playerStats']"/>
</xsl:template>
<xsl:template match="array">
<BallerStats>
<xsl:apply-templates/>
</BallerStats>
</xsl:template>
<xsl:template match="map">
<BallerStat>
<xsl:apply-templates/>
</BallerStat>
</xsl:template>
<xsl:template match="*[@key='jerseyNumber']">
<Baller>
<BallerJersey xsl:expand-text="true">{.}</BallerJersey>
<Type>Jersey</Type>
</Baller>
</xsl:template>
<xsl:template match="*[@key='fgPercentage']">
<fgPercentage>
<Type>PERCENT</Type>
<Value xsl:expand-text="true">{.}</Value>
</fgPercentage>
</xsl:template>
<xsl:template match="*[@key=('plusMinus')]"/>
</xsl:stylesheet>
Output (stdout)
<?xml version="1.0" encoding="UTF-8"?>
<BallerStats>
<BallerStat>
<Baller>
<BallerJersey>23</BallerJersey>
<Type>Jersey</Type>
</Baller>
<fgPercentage>
<Type>PERCENT</Type>
<Value>60</Value>
</fgPercentage>
</BallerStat>
<BallerStat>
<Baller>
<BallerJersey>24</BallerJersey>
<Type>Jersey</Type>
</Baller>
<fgPercentage>
<Type>PERCENT</Type>
<Value>40</Value>
</fgPercentage>
</BallerStat>
</BallerStats>
Answered By - Daniel Haley
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.