I have some xml data with multiple Name nodes. Based on the presence or absence of id node, I need to segregate the nodes. On converting to JSON, I want all the similar nodes to be merged into an JSON array. Below is my XML data
<Names>
<CustName>
<Name>Name1</Name>
<id>3</id>
</CustName>
<CustName >
<Name>Name2</Name>
</CustName>
<CustName>
<Name>Name3</Name>
<id>32</id>
</CustName>
</Names>
The XSLT that I have tried is as follows. But this creates two nodes for Update and one node for Create. Whereas I want 1st and 3rd Name nodes to be under Update node and 2nd Name node under Create
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="no" method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/">
<CustomerNames>
<xsl:for-each select="//Names/CustName">
<xsl:choose>
<xsl:when test="id !=''">
<Update>
<CustName>
<xsl:value-of select="Name"/>
</CustName>
<id>
<xsl:value-of select="id"/>
</id>
</Update>
</xsl:when>
<xsl:otherwise>
<Create>
<CustName>
<xsl:value-of select="Name"/>
</CustName>
</Create>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</CustomerNames>
</xsl:template>
</xsl:stylesheet>
Transformed xml should look like:
<CustomerNames>
<Update>
<CustName>Name1</CustName>
<id>3</id>
</Update>
<Update>
<CustName>Name3</CustName>
<id>32</id>
</Update>
<Create>
<Name>Name2</Name>
</Create>
</CustomerNames>
On converting to json, I want the similar nodes to be appended in an array. Like this
{
"CustomerNames":{
"Update":[
{
"CustName":"Name1",
"id":"3"
},
{
"CustName":"Name3",
"id":"32"
}
],
"Create":[
{
"Name":"Name2"
}
]
}
}
How can I achieve this in XSL 1.0?
CodePudding user response:
It seems the order nodes are placed matters when auto-converting XML to a JSON. Hence update your XSLT to something like the one below.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="no" method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/">
<CustomerNames>
<xsl:for-each select="//Names/CustName[id]">
<Update>
<CustName>
<xsl:value-of select="Name"/>
</CustName>
<id>
<xsl:value-of select="id"/>
</id>
</Update>
</xsl:for-each>
<xsl:for-each select="//Names/CustName[not(id)]">
<Create>
<CustName>
<xsl:value-of select="Name"/>
</CustName>
</Create>
</xsl:for-each>
</CustomerNames>
</xsl:template>
</xsl:stylesheet>
CodePudding user response:
Alternatively, you can group the XML nodes by using XSL Sort
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="no" method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/">
<CustomerNames xmlns="">
<xsl:for-each select="//Names/CustName">
<xsl:sort select="id"/>
<xsl:choose>
<xsl:when test="id !=''">
<Update>
<CustName>
<xsl:value-of select="Name"/>
</CustName>
<id>
<xsl:value-of select="id"/>
</id>
</Update>
</xsl:when>
<xsl:otherwise>
<Create>
<CustName>
<xsl:value-of select="Name"/>
</CustName>
</Create>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</CustomerNames>
</xsl:template>
</xsl:stylesheet>
CodePudding user response:
Another approach would be to use the Payloadfactry mediator after the XSLT mediator to group the nodes.Example below.
<payloadFactory media-type="xml">
<format>
<CustomerNames>
$1
$2
</CustomerNames>
</format>
<args>
<arg expression="//Update"/>
<arg expression="//Create"/>
</args>
</payloadFactory>