Converting json array to xml using XSLT

i have a front end page that send a request to an data service deployed to wso2 console for doing an update in a table. The problem is that i need to convert the json array from the front end to an xml format for build the payload factory for the request. The json is :

{"cdcList":
["UpdateCdc":
    {
 "idCdc":1,
     "order":1,
     "cdcName":"test 1",
    },
 "UpdateCdc":
    {
     "idCdc":2,
 "order":2,
     "cdcName":"test 2",
     "idParent":1
    },
  "UpdateCdc":
    {
     "idCdc":3,
     "order":1,
     "cdcName":"test 3",
     "idParent":1
     }
]

}

and the desired result in xml that i would like that it will be is :

<cdcList>
          <UpdateCdc>
        <idCdc>1</idCdc>
        <order>1</order>
            <cdcName>test 1</cdcName>
          </UpdateCdc>
          <UpdateCdc>
            <idCdc>2</idCdc>
            <order>2</order>
            <cdcName>test 2</cdcName>
            <idParent>1</idParent>
          </UpdateCdc>
          <UpdateCdc>
            <idCdc>3</idCdc>
            <order>3</order>
            <cdcName>test 3</cdcName>
            <idParent>1</idParent>
          </UpdateCdc>
</cdcList>

Thank you.

Upvotes: 1

Views: 3467

Answers (2)

Martin Honnen
Martin Honnen

Reputation: 167401

While Michael Kay's answer gives you XML (see it online at https://xsltfiddle.liberty-development.net/bFDb2Cf/) I think it has one shortcoming, the order of the keys of an XPath 3.1 map is not defined so with map:keys you might get any order for the child elements (e.g. in the linked example it is idParent, idCdc, cdcName, order) while you probably want to define the order for the child elements based on the order in the JSON. That can be achieved using the json-to-xml function already mentioned by Tim in a comment:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:fn="http://www.w3.org/2005/xpath-functions"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:array="http://www.w3.org/2005/xpath-functions/array"
    exclude-result-prefixes="xs math map array fn"
    version="3.0">

  <xsl:output method="xml" indent="yes"/>

  <xsl:param name="json-input" as="xs:string">[
    {
        "idCdc": 1,
        "order": 1,
        "cdcName": "test 1"
    },
    {
        "idCdc": 2,
        "order": 2,
        "cdcName": "test 2",
        "idParent": 1
    },
    {
        "idCdc": 3,
        "order": 1,
        "cdcName": "test 3",
        "idParent": 1
    }
]</xsl:param>

  <xsl:variable name="json-array" select="parse-json($json-input)"/>

  <xsl:variable name="json-xml" select="json-to-xml($json-input)"/>

  <xsl:template match="/">
    <cdcList>
        <xsl:apply-templates select="$json-xml/*"/>
    </cdcList>
  </xsl:template>

  <xsl:template match="fn:map">
      <updateCdc>
          <xsl:apply-templates/>
      </updateCdc>
  </xsl:template>

  <xsl:template match="fn:map/fn:*">
      <xsl:element name="{@key}">
          <xsl:value-of select="."/>
      </xsl:element>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/bFDb2Cf/2 has that example, in https://xsltfiddle.liberty-development.net/bFDb2Cf/1 I also output the result of the json-to-xml call so that you can see how the JSON input is mapped to XML:

<array xmlns="http://www.w3.org/2005/xpath-functions">
   <map>
      <number key="idCdc">1</number>
      <number key="order">1</number>
      <string key="cdcName">test 1</string>
   </map>
   <map>
      <number key="idCdc">2</number>
      <number key="order">2</number>
      <string key="cdcName">test 2</string>
      <number key="idParent">1</number>
   </map>
   <map>
      <number key="idCdc">3</number>
      <number key="order">1</number>
      <string key="cdcName">test 3</string>
      <number key="idParent">1</number>
   </map>
</array>

Upvotes: 2

Michael Kay
Michael Kay

Reputation: 163262

To do client-side processing in XSLT with support for JSON parsing you will need an XSLT 3.0 processor, which in practice means Saxon-JS. (Disclaimer: that's my company's product.)

Unfortunately the input you supplied isn't valid JSON, but let's assume it is actually like this:

[
    {
        "idCdc": 1,
        "order": 1,
        "cdcName": "test 1"
    },
    {
        "idCdc": 2,
        "order": 2,
        "cdcName": "test 2",
        "idParent": 1
    },
    {
        "idCdc": 3,
        "order": 1,
        "cdcName": "test 3",
        "idParent": 1
    }
]

Then you can convert it to your desired XML format using the following XSLT 3.0 code:

<xsl:variable name="json-array" select="json-doc('input.json')"/>
<cdcList>
  <xsl:for-each select="$json-array?*">
    <updateCdc>
      <xsl:for-each select="map:keys(.)">
         <xsl:element name="{.}">
           <xsl:value-of select="map:get(.)"/>
         </xsl:element>
      </xsl:for-each>
    </updateCdc>
  </xsl:for-each>
</cdcList>

Upvotes: 2

Related Questions