How to iterate Json Array in Xslt 4.0

60 Views Asked by At

sample.json:

{
"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"
        }
    }
]

}

sample.xslt:

<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',
                                                          'identifier' : map {'name' : array{?sellers?books?*?Name}} 
                                                        } }"/>
     </xsl:template> 
 </xsl:stylesheet>
                                    

I have applied the logic as I got replied in my previous question How to extract value from json object in xslt mapping. It's perfectly working for that requirement.

But as the json has been changed and I changed the logic little bit, then I got the error as SERE0023 JSON serialization: cannot handle a sequence of length 2 ("C", "C++"), then I have applied array just before getting the name of the books. This error got resolved after that. But I am unable to get the desired result.

I am getting below json as output, which doesn't meet the requirement

wrongOutput.json:

        [
        {
            "resourceType": "Asset",
            "indentifier": {
                "name": [
                    "C",
                    "C++"
                ]
            }
        },
        {
            "resourceType": "Asset",
            "indentifier": {
                "name": [
                    "Python",
                    "Java"
                ]
            }
        }
    ]
                                
    But expected output should be as below
                                
        **result.json**
     [
                                      {
                                        "resourceType": "Asset",
                                        "indentifier": { "name":"C" }
                                      },
                                      {
                                        "resourceType": "Asset",
                                        "indentifier": { "name":"C++" }
                                      },
                                      {
                                        "resourceType": "Asset",
                                        "indentifier": { "name":"Python" }
                                      },
                                      {
                                        "resourceType": "Asset",
                                        "indentifier": { "name":"Java" }
                                      }
                                    ]`
                                   
                                    

I have also tried with adding for-each loop as below, 'indentifier' : map {'name' : for-each{array{?seller?books?*?Name}}} But I am getting the error as XPST0003 Node constructor expressions are allowed only in XQuery, not in XPath

1

There are 1 best solutions below

3
Martin Honnen On

Presuming you have e.g.

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

you probably want XSLT alike

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.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?*?sellers?books?* ! map {
                  'resourceType' : 'Asset',
                  'indentifier' : ?Name
                }
              }"/>
  </xsl:template> 
  
</xsl:stylesheet>

or perhaps for the inner identifier being itself a map/a JSON object

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.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?*?sellers?books?* ! map {
                  'resourceType' : 'Asset',
                  'indentifier' : map { 'name': ?Name }
                }
              }"/>
  </xsl:template> 
  
</xsl:stylesheet>

For the changed input it would be rather

   <xsl:template match="." name="xsl:initial-template">
    <xsl:sequence 
      select="array { 
                ?publishers?*?seller?books?* ! map {
                  'resourceType' : 'Asset',
                  'indentifier' : map { 'name': ?Name }
                }
              }"/>
  </xsl:template>

but perhaps you want to insert another property in the output as well; ask a new question if you can't get it to work on your own.