简体   繁体   中英

Converting a JSON file to a specific XML format

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.

  1. Scan Json and look for "playerStats"
  2. If not found , Do nothing.
  3. If found then grab valuable information like jerseyNumber , fgPercentage, ignore plusMinus and store them in a object of a template class with these Values.
  4. 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.

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>

Underscore-java library can convert json to xml. I am the maintainer of the project. Live example

import com.github.underscore.lodash.U;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class MyClass {
    @SuppressWarnings("unchecked")
    public static void main(String args[]) {
        String json = "{\"playerStats\": [\n"
        + "{ \"jerseyNumber\": \"23\",  \"fgPercentage\": 60, \"plusMinus\": \"plus\" },"
        + "{ \"jerseyNumber\": \"24\",  \"fgPercentage\": 40, \"plusMinus\": \"minus\" }"
        + "] }";
    String xml = "<BallerStats>"
        + "<BallerStat>"
        + "    <Baller><BallerJersey>23</BallerJersey><Type>Jersey</Type></Baller>"
        + "    <fgPercentage><Type>PERCENT</Type><Value>60</Value></fgPercentage>"
        + "</BallerStat>"
        + "</BallerStats>";

    List<Map<String, Object>> jsonArray = U.get((Map<String, Object>) U.fromJson( json ), "playerStats");
    Map<String, Object> map = new LinkedHashMap<>();
    List<Map<String, Object>> ballerStats = new ArrayList<>();
    Map<String, Object> ballerStat = new LinkedHashMap<>();
    map.put("BallerStats", ballerStat);
    ballerStat.put("BallerStat", ballerStats);
    for (Map<String, Object> jsonItem : jsonArray) {
        Map<String, Object> newBallerStat = (Map<String, Object>) ((Map<String, Object>) ((Map<String, Object>) U.fromXml( xml )).get("BallerStats")).get("BallerStat");
        ((Map<String, Object>) newBallerStat.get("Baller")).put("BallerJersey", jsonItem.get("jerseyNumber"));
        ((Map<String, Object>) newBallerStat.get("fgPercentage")).put("Value", jsonItem.get("fgPercentage"));
        ballerStats.add(newBallerStat);
    }
    System.out.println(U.toXml(map)); 
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM