How to iterate a json array in xslt

57 views Asked by At

I have the below sample.json as input

{
    "publishers": [
        {
            "sellers": {
                "books": [
                    {
                        "test": {
                            "count": 1
                        },
                        "Name": "C",
                        "Type": "String"
                    },
                    {
                        "test": {
                            "count": 2
                        },
                        "Name": "C++",
                        "Type": "String"
                    }
                ],
                "Author": "Michel"
            }
        },
        {
            "sellers": {
                "books": [
                    {
                        "test": {
                            "count": 3
                        },
                        "Name": "Python",
                        "Type": "String"
                    },
                    {
                        "test": {
                            "count": 4
                        },
                        "Name": "Java",
                        "Type": "String"
                    }
                ],
                "Author": "Robert"
            }
        }
    ]
} 

And this stylesheet:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
              version="4.0"
              xmlns:xs="http://www.w3.org/2001/XMLSchema"
              exclude-result-prefixes="#all">
              
              <xsl:output method="json" indent="yes"/>
            
               <xsl:template match="." name="xsl:initial-template">
                <xsl:sequence 
                  select="array { 
                            ?publishers?* ! map {
                              'resourceType' : 'Asset',
                              'indentifier' : map {'name' : array{?sellers?books?*?Name}},
                              'author' : map{'name' : ?sellers?Author}
                             
                            }
                          }"/>
              </xsl:template> 
              
            </xsl:stylesheet>

I am getting the below json output:

    [
              {
                "resourceType": "Asset",
                "author": { "name":"Michel" },
                "indentifier": { "name":[ "C", "C++" ] }
              },
              {
                "resourceType": "Asset",
                "author": { "name":"Robert" },
                "indentifier": { "name":[ "Python", "Java" ] }
              }
            ]

But desired output is as below:

    [
                  {
                    "resourceType": "Asset",
                    "author": { "name":Michel },
                    "indentifier": { "name":"C" }
                  },
                  {
                    "resourceType": "Asset",
                    "author": { "name":Michel },
                    "indentifier": { "name":"C++" }
                  },
                  {
                    "resourceType": "Asset",
                    "author": { "name":Robert },
                    "indentifier": { "name":"Python" }
                  },
                  {
                    "resourceType": "Asset",
                    "author": { "name":Robert },
                    "indentifier": { "name":"Java" }
                  }
                ]

I have also tried with adding a for-each loop as below:

'indentifier' : map {'name' : for-each{array{?seller?books?*?Name}}} 

But I am getting the error

XPST0003 Node constructor expressions are allowed only in XQuery, not in XPath

If I put select="array { publishers?*?sellers?books?*} it is working fine to get the names of the book. But I am not getting the value of "author" in ouput.json as it's inside "sellers". So I tried with select="array {?publishers?*}, so that I can get the value of author. But I didn't get the desired output in "name" field.

1

There are 1 answers

1
Martin Honnen On

I think here it makes sense to use a for expression to bind a variable, you can do that in XPath 4 as

<xsl:template match="." name="xsl:initial-template">
    <xsl:sequence 
      select="array { 
                for $seller in ?publishers?*?sellers
                for $book in $seller?books?*
                return map {
                  'resourceType' : 'Asset',
                  'indentifier' : map {'name' : $book?Name },
                  'author' : map{'name' : $seller?Author}                
                }
              }"/>
</xsl:template> 

I think, for XPath 3.1 you need

<xsl:template match="." name="xsl:initial-template">
    <xsl:sequence 
      select="array { 
                for $seller in ?publishers?*?sellers
                return
                for $book in $seller?books?*
                return map {
                  'resourceType' : 'Asset',
                  'indentifier' : map {'name' : $book?Name },
                  'author' : map{'name' : $seller?Author}                
                }
              }"/>
</xsl:template>