user9324800
user9324800

Reputation: 163

XSLT: Merge two nodes

I would like to convert below XML through XSLT by groping based on Email tag and merge two nodes into one and get all the elements in one node. Please advise

Input XML:

<?xml version="1.0" encoding="UTF-8"?>
<Details>  
    <Worker>
        <Name>AAA</Name>
        <Email>[email protected]</Email>
        <Item>BBB</Item>
        <Avg_Amount>425.20</Avg_Amount>
    </Worker>
    <Worker>
        <Manager>AAA</Manager>
        <Email>[email protected]</Email>
        <Item>BBB</Item>
        <Draft_Amount>1826.64</Draft_Amount>
    </Worker>   
</Details>

XSLT:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:wd="urn:com.test/bsvc" exclude-result-prefixes="wd">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
    
    <xsl:template match="/">
        
        <Transactions>
            
            <xsl:for-each-group select="Details/Worker" group-by='Email'>
                
                <Manager>             
                    <Name>
                        <xsl:value-of select="Name"/>
                    </Name>
                    <Email>
                        <xsl:value-of select="Email"/>
                    </Email>
                    
                    
                    <xsl:for-each-group select="current-group()" group-by="Item">
                        
                        <Worker>
                            <Name>
                                <xsl:value-of select="Name"/>
                            </Name>
                            <Email>
                                <xsl:value-of select="Email"/>
                            </Email>
                            <Item>
                                <xsl:value-of select="Item"/>
                            </Item>
                            
                            <Avg_Amount>
                                <xsl:value-of select="Avg_Amount"/>
                            </Avg_Amount>
                            <Draft_Amount>
                                <xsl:value-of select="Charges_Draft"/>
                            </Draft_Amount>
                            
                            
                        </Worker>
                        
                        
                        
                    </xsl:for-each-group>
                    
                </Manager>
                
            </xsl:for-each-group>
            
        </Transactions>
    </xsl:template>
</xsl:stylesheet>

Output generated:

<Transactions>
   <Manager>
      <Name>AAA</Name>
      <Email>[email protected]</Email>
      <Worker>
         <Name>AAA</Name>
         <Email>[email protected]</Email>
         <Item>BBB</Item>
         <Avg_Amount>425.20</Avg_Amount>
         <Draft_Amount/>
      </Worker>
   </Manager>
</Transactions>

Desired Output:

<Transactions>
   <Manager>
      <Name>AAA</Name>
      <Email>[email protected]</Email>
      <Worker>
         <Name>AAA</Name>
         <Email>[email protected]</Email>
         <Item>BBB</Item>
         <Avg_Amount>425.20</Avg_Amount>
         <Draft_Amount>1826.64</Draft_Amount>
      </Worker>
   </Manager>
</Transactions>

I would like to convert below XML through XSLT by groping based on Email tag and merge two nodes into one and get all the elements in one node. Please advise

Upvotes: 1

Views: 392

Answers (1)

Mads Hansen
Mads Hansen

Reputation: 66851

Change the Draft_Amount to select Draft_Amount from the current-group():

<Draft_Amount>
  <xsl:value-of select="current-group()/Draft_Amount"/>
</Draft_Amount>

But should consider what you would want to do if there are more than one Draft_Amount among multiple Worker. You could average them, select the first, etc.

Also, your example data only has one Avg_Amount element, but you might consider changing Avg_Amount to compute the average of all Avg_Amount.

<Avg_Amount>
  <xsl:value-of select="avg(current-group()/Avg_Amount)"/>
</Avg_Amount>

You could eliminate the extra xsl:for-each, and could simplify the code a bit and just copy some of those elements, instead of recreating the element and selecting the values:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:wd="urn:com.test/bsvc" exclude-result-prefixes="wd">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
    
    <xsl:template match="/"> 
        <Transactions>
            <xsl:for-each-group select="Details/Worker" group-by='Email'>     
                <Manager>   
                    <xsl:copy-of select="Name|Email"/>
                    <Worker>
                        <xsl:copy-of select="Name|Email|Item"/>
                        <Avg_Amount>
                            <xsl:value-of select="avg(current-group()/Avg_Amount)"/>
                        </Avg_Amount>
                        <xsl:copy-of select="(current-group()/Draft_Amount)[1]"/>
                    </Worker>
                </Manager>
            </xsl:for-each-group>
        </Transactions>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 1

Related Questions