Created new XSLT process using below XML DATA. When I use output method = "text" below XSLT code working but output method changed to (Method="json") XSLT process failing. my goal generate file/data as JSON.
Note: I am looking generic process. My XSLT code implemented as generic method and NO HARDCODED columns in XSLT code.
-- XML Data
<wd:Report_Data xmlns:wd="urn:com.workday.report/EntryReason">
<wd:Report_Entry>
<wd:EntryReasonRefID>ABC_123</wd:EntryReasonRefID>
<wd:EntryReason>ABC_123 Reimbursement - Non Taxable</wd:EntryReason>
<wd:CreatedMoment>2022-08-30T18:35:34.040-07:00</wd:CreatedMoment>
<wd:LastFunctionallyUpdated>2022-09-01T12:37:48.427-07:00</wd:LastFunctionallyUpdated>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:EntryReasonRefID>ABC_456</wd:EntryReasonRefID>
<wd:EntryReason>ABC_456 - Air Travel</wd:EntryReason>
<wd:CreatedMoment>2022-08-30T18:35:34.370-07:00</wd:CreatedMoment>
<wd:LastFunctionallyUpdated>2022-09-01T12:37:48.552-07:00</wd:LastFunctionallyUpdated>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:EntryReasonRefID>ABC_789</wd:EntryReasonRefID>
<wd:EntryReason>ABC_789 - Car Rental</wd:EntryReason>
<wd:CreatedMoment>2022-08-30T18:35:34.501-07:00</wd:CreatedMoment>
<wd:LastFunctionallyUpdated>2022-09-01T12:37:48.672-07:00</wd:LastFunctionallyUpdated>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:EntryReasonRefID>ABC_999</wd:EntryReasonRefID>
<wd:EntryReason>ABC_999 - Hotel</wd:EntryReason>
<wd:EntryReason>ABC_999 - Rental</wd:EntryReason>
<wd:CreatedMoment>2022-08-30T18:35:34.636-07:00</wd:CreatedMoment>
<wd:LastFunctionallyUpdated>2022-09-01T12:37:48.779-07:00</wd:LastFunctionallyUpdated>
</wd:Report_Entry>
</wd:Report_Data>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wd="urn:com.workday.report/EntryReason" version="3.0">
<xsl:output method="json" indent="yes"/>
<xsl:template match="/wd:Report_Data">
<xsl:text> [
</xsl:text>
<xsl:for-each select="wd:Report_Entry">
<xsl:text> {
</xsl:text>
<xsl:for-each select="./*">
<xsl:text> </xsl:text>
<xsl:choose>
<xsl:when test="@wd:Descriptor"><xsl:value-of select="concat('"',local-name(),'":"',@wd:Descriptor,'"')"/></xsl:when>
<xsl:otherwise><xsl:value-of select="concat('"',local-name(),'":"',.,'"')"/></xsl:otherwise>
</xsl:choose>
<xsl:if test="position() != last()">
<xsl:text>,
 </xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>
  }</xsl:text>
<xsl:if test="position() != last()">
<xsl:text>,
</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>
 ]</xsl:text>
</xsl:template>
<xsl:template match="node() | @*"/>
</xsl:stylesheet>
--Error Details :
Error executing XSLT at line 8 : JSON output method cannot handle sequences of two or more items
//Expected Result as output Method = json :
[
{
"EntryReasonRefID": "ABC_123 Reimbursement - Non Taxable",
"EntryReason": "ABC_123",
"CreatedMoment": "2022-08-30T18:35:34.040-07:00",
"LastFunctionallyUpdated": "2022-09-01T12:37:48.427-07:00"
},
{
"EntryReasonRefID": "ABC_456 - Air Travel",
"EntryReason": "ABC_456",
"CreatedMoment": "2022-08-30T18:35:34.040-07:00",
"LastFunctionallyUpdated": "2022-09-01T12:37:48.427-07:00"
},
{
"EntryReasonRefID": "ABC_789 - Car Rental",
"EntryReason": "ABC_789",
"CreatedMoment": "2022-08-30T18:35:34.040-07:00",
"LastFunctionallyUpdated": "2022-09-01T12:37:48.427-07:00"
},
{
"EntryReasonRefID": "ABC_999 - Hotel; ABC_999 - Rental",
"EntryReason": "ABC_999",
"CreatedMoment": "2022-08-30T18:35:34.040-07:00",
"LastFunctionallyUpdated": "2022-09-01T12:37:48.427-07:00"
}
]
You don't say what happens when you run your code, only that it's "failing". You really should report the error message you receive, because it can be helpful to people trying to help you.
I am guessing it fails because your stylesheet produces as output a sequence of text nodes, and tries to serialize that as JSON, which should produce a serialization error err:SERE0023 because a sequence of more than one item is not a valid JSON document.
To produce JSON output your stylesheet should do either one of these two things:
text
output method to convert that sequence to a single stringjson
output method to serialize that data structure as JSON.You have generated a plain text representation of a serialized JSON object (an array), but you've used the json
output method instead of the text
output method to serialize it. NB you haven't dealt with escaping text which might contain a "
character.
An alternative and better approach would be generate an array of maps, and serialize that array using the json
output method. There are various ways you could do that. One way would be to generate fn:array
, fn:map
, fn:string
etc XML elements and then convert that data structure to JSON using the xml-to-json
XPath function. In this case the conversion is simple enough that you can do the whole thing in a single XPath expression:
<xsl:stylesheet
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wd="urn:com.workday.report/EntryReason" version="3.0">
<xsl:output method="json" indent="yes"/>
<xsl:template match="/wd:Report_Data">
<xsl:sequence select="
array{
for $entry in wd:Report_Entry return map:merge(
for $element in $entry/* return map{
local-name($element):
string-join(
for $value in
$entry/*[local-name()=local-name($element)]
return
string($element),
'; '
)
}
)
}
"/>
</xsl:template>
</xsl:stylesheet>
The XPath expression in that xsl:sequence
statement means: