Home > Enterprise >  Appending nodes with similar names using xslt in wso2
Appending nodes with similar names using xslt in wso2

Time:01-31

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>
  • Related