skip to Main Content

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?

3

Answers


  1. 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>
    
    Login or Signup to reply.
  2. 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>
    
    Login or Signup to reply.
  3. 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>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search