skip to Main Content

I have to take the input as JSON and transform it to another JSON by using XSLT.

Input JSON:

{
  "members": [
    {
      "name": "Molecule Man1",
      "age": 29,
      "secretIdentity": "Dan Jukes"
    },
    {
      "name": "Molecule Man2",
      "age": 30,
      "secretIdentity": "Martin"
    }
  ]
}

I want to convert the above JSON to look like this:

{
   "resourceType": "Test",
   "type": {
      "name": "Member"
   },
   "displayName": "Molecule Man",
   "attributes": {
      "test": [
         {
            "value": "29"
         }
      ],
      "testing": [
         {
            "value": "Dan Jukes"
         }
      ]
   }
}

I have tried with the below code and am not able to get the desired output JSON. I am getting an error SERE0023 JSON serialization: cannot handle a sequence of length 2 and also getting the error as saxon:array is not recognized as Saxon instruction.Saxon extensions require Saxon-PE or higher, while trying to implement <saxon::array> .

I have used Saxon HE(12.0) dependency.

Java Code

package com.practice;

import net.sf.saxon.s9api.*;
import javax.xml.transform.stream.StreamSource;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.InputStreamReader;

import java.nio.charset.StandardCharsets;

public class JsonToXsltToJson {
    public static void main(String[] args) throws FileNotFoundException, SaxonApiException {
        Processor processor = new Processor(false);
        TransformJson(processor);
    }

    static void TransformJson(Processor processor) throws 
 FileNotFoundException, SaxonApiException {
       
        JsonBuilder jsonBuilder = processor.newJsonBuilder();
        XdmValue input = jsonBuilder.parseJson(new InputStreamReader(new FileInputStream("input.json"), StandardCharsets.UTF_8));
        XsltCompiler xsltCompiler = processor.newXsltCompiler();
        XsltExecutable xsltExecutable = xsltCompiler.compile(new StreamSource(new File("jsonTransform.xsl")));
        Xslt30Transformer xslt30Transformer = xsltExecutable.load30();
        xslt30Transformer.applyTemplates(input, xslt30Transformer.newSerializer(System.out));

    }
}

sample.xsl:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="3.0"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:map="http://www.w3.org/2005/xpath-functions/map"
                xmlns:mf="http://example.com/mf" 
                exclude-result-prefixes="#all">

    <xsl:param name="nodes" as="map(*)*"/>

    <xsl:template name="init">
        <xsl:apply-templates select="($nodes)"/>
    </xsl:template>

    <xsl:template  match=".">
        <xsl:map>
            <xsl:map-entry key="'resourceType'" select="'Test'"/>
            <xsl:map-entry key="'type'">
            <xsl:map-entry key="'name'" select="'Member'"/>
            </xsl:map-entry>
            <xsl:map-entry key="'displayName'" select= "?members?1?name"/>
            <xsl:map-entry key="'attributes'">
            <xsl:map-entry key="'age'">
            <xsl:map-entry key="'value'" select="?members?1?age"/>
            </xsl:map-entry>
                <xsl:map-entry key="'secretIdentity'">
                    <xsl:map-entry key="'value'" select="?members?1?secretIdentity"/>
                </xsl:map-entry>
            </xsl:map-entry>
        </xsl:map>
    </xsl:template>
    <xsl:output method="json" indent="yes"/>
</xsl:stylesheet>
```

2

Answers


  1. I think you want a nested map:

        <xsl:map>
            <xsl:map-entry key="'resourceType'" select="'Test'"/>
            <xsl:map-entry key="'type'">
              <xsl:map-entry key="'name'" select="'Member'"/>
            </xsl:map-entry>
            <xsl:map-entry key="'displayName'" select= "?members?1?name"/>
            <xsl:map-entry key="'attributes'">
              <xsl:map>
                <xsl:map-entry key="'test'" select="[?members?1?age]"/>
                <xsl:map-entry key="'testing'" select="[?members?1?secretIdentity]"/>
              </xsl:map>
            </xsl:map-entry>
        </xsl:map>
    

    And for

            <xsl:map-entry key="'test'" select="[?members?1?age]"/>
            <xsl:map-entry key="'testing'" select="[?members?1?secretIdentity]"/>
    

    you might

            <xsl:map-entry key="'test'" select="[map { 'value' : ?members?1?age }]"/>
            <xsl:map-entry key="'testing'" select="[map { 'value' : ?members?1?secretIdentity }]"/>
    
    Login or Signup to reply.
  2. You could also do this all in XPath:

    <xsl:sequence select="
      map{'resourceType':'Test',
          'type':map{'name':'Member'},
          'displayName': ?members?1?name,
          'attributes': map{
              'test': [?members?1?age],
              'testing': [?members?1?secretIdentity]}
         }"/>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search