Karuna
Karuna

Reputation: 53

XSLT : Parse with multiple same name

As the below source XML Value/string element value has to be replace with target element value, Could some please help me out how to create the XSL to transform from source xml into target xml .Please.

Source XML:

 <PricingResultsV6>     
 <subItems>
 <SubItem>   
 <profiles>
 <ProfileValues>
 <values> 
 <strings>800210</strings> 
 <strings>THC</strings> 
 <strings>10.0</strings> 
 <strings>20.0</strings> 
 <strings>30.0</strings> 
 <strings>40.0</strings> 
 <strings>550.0</strings> 
 <strings>640.0</strings> 
 </values>
</ProfileValues>
</rofiles>
</SubItem>
</subItems>
</PricingResultsV6>

Target XML :

<CalculationOutput>
            <PolicyNumber> 800210 </PolicyNumber>
            <CommissionFactorMultiplier> THC </CommissionFactorMultiplier>
            <PremiumValue>10.0</PremiumValue>
            <SalesmanCommissionValue>20.0</SalesmanCommissionValue>
            <ManagerCommissionValue>30.0</ManagerCommissionValue>
            <GL_COR> 550.0</GL_COR>
            <GL_OPO>640.0</GL_OPO>

</CalculationOutput>

Upvotes: 2

Views: 1344

Answers (3)

Daniel Haley
Daniel Haley

Reputation: 52878

Ugh. I just answered the exact duplicate to this question.

Since both of my XSLT 1.0 examples and my XSLT 2.0 example are covered by Dimitre's and Kirill's answers, I'll add my XSLT 3.0 answer...

XML Input

<PricingResultsV6>
    <subItems>
        <SubItem>
            <profiles>
                <ProfileValues>
                    <values>
                        <strings>800210</strings>
                        <strings>THC</strings>
                        <strings>10.0</strings>
                        <strings>20.0</strings>
                        <strings>30.0</strings>
                        <strings>40.0</strings>
                        <strings>550.0</strings>
                        <strings>640.0</strings>
                    </values>
                </ProfileValues>
            </profiles>
        </SubItem>
    </subItems>
</PricingResultsV6>

XSLT 3.0 (tested with Saxon-EE 9.4)

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    exclude-result-prefixes="map">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:variable name="vMap" select="map {
        1:='PolicyNumber',
        2:='CommissionFactorMultiplier',
        3:='PremiumValue',
        4:='SalesmanCommissionValue',
        5:='ManagerCommissionValue',
        7:='GL_COR',
        8:='GL_OPO',
        }"/>

    <xsl:template match="ProfileValues">
        <CalculationOutput>
            <xsl:apply-templates select="values/strings"/>
        </CalculationOutput>
    </xsl:template>

    <xsl:template match="strings[map:contains($vMap,position())]">      
        <xsl:element name="{map:get($vMap,position())}">
            <xsl:value-of select="."/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="text()"/>

</xsl:stylesheet>

XML Output

<CalculationOutput>
   <PolicyNumber>800210</PolicyNumber>
   <CommissionFactorMultiplier>THC</CommissionFactorMultiplier>
   <PremiumValue>10.0</PremiumValue>
   <SalesmanCommissionValue>20.0</SalesmanCommissionValue>
   <ManagerCommissionValue>30.0</ManagerCommissionValue>
   <GL_COR>550.0</GL_COR>
   <GL_OPO>640.0</GL_OPO>
</CalculationOutput>

Upvotes: 1

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243529

This generic transformation allows separate (even in a different document or passed as external parameter) mapping between the strings elements and the corresponding element name that must be generated:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my" exclude-result-prefixes="my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <my:mapping>
  <map key="1" value="PolicyNumber"/>
  <map key="2" value="CommissionFactorMultiplier"/>
  <map key="3" value="PremiumValue"/>
  <map key="4" value="SalesmanCommissionValue"/>
  <map key="5" value="ManagerCommissionValue"/>
  <map key="7" value="GL_COR"/>
  <map key="8" value="GL_OPO"/>
 </my:mapping>
 <xsl:variable name="vMaps" select="document('')/*/my:mapping/*"/>  

 <xsl:template match="values">
     <CalculationOutput>
       <xsl:apply-templates/>
     </CalculationOutput>
 </xsl:template>

 <xsl:template match="strings">
  <xsl:if test="position()=$vMaps/@key">
    <xsl:variable name="vPos" select="position()"/>
    <xsl:element name="{$vMaps[@key = $vPos]/@value}">
      <xsl:value-of select="."/>
    </xsl:element>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<PricingResultsV6>
    <subItems>
        <SubItem>
            <profiles>
                <ProfileValues>
                    <values>
                        <strings>800210</strings>
                        <strings>THC</strings>
                        <strings>10.0</strings>
                        <strings>20.0</strings>
                        <strings>30.0</strings>
                        <strings>40.0</strings>
                        <strings>550.0</strings>
                        <strings>640.0</strings>
                    </values>
                </ProfileValues>
            </profiles>
        </SubItem>
    </subItems>
</PricingResultsV6>

the wanted, correct result is produced:

<CalculationOutput>
   <PolicyNumber>800210</PolicyNumber>
   <CommissionFactorMultiplier>THC</CommissionFactorMultiplier>
   <PremiumValue>10.0</PremiumValue>
   <SalesmanCommissionValue>20.0</SalesmanCommissionValue>
   <ManagerCommissionValue>30.0</ManagerCommissionValue>
   <GL_COR>550.0</GL_COR>
   <GL_OPO>640.0</GL_OPO>
</CalculationOutput>

II. This solution can be made very efficient by using keys:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my" exclude-result-prefixes="my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <my:mapping>
  <map key="1" value="PolicyNumber"/>
  <map key="2" value="CommissionFactorMultiplier"/>
  <map key="3" value="PremiumValue"/>
  <map key="4" value="SalesmanCommissionValue"/>
  <map key="5" value="ManagerCommissionValue"/>
  <map key="7" value="GL_COR"/>
  <map key="8" value="GL_OPO"/>
 </my:mapping>
 <xsl:variable name="vMaps" select="document('')/*/my:mapping/*"/>  

 <xsl:key name="kValueByKey" match="@value" use="../@key"/>

 <xsl:template match="values">
     <CalculationOutput>
       <xsl:apply-templates/>
     </CalculationOutput>
 </xsl:template>

 <xsl:template match="strings">
  <xsl:if test="position()=$vMaps/@key">
    <xsl:variable name="vPos" select="position()"/>
    <xsl:variable name="vCur" select="."/>
     <xsl:for-each select="$vMaps/..">
        <xsl:element name="{key('kValueByKey', $vPos)}">
          <xsl:value-of select="$vCur"/>
        </xsl:element>
     </xsl:for-each>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

Upvotes: 0

Kirill Polishchuk
Kirill Polishchuk

Reputation: 56182

Use:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" />

    <xsl:template match="//values">
        <CalculationOutput>
            <PolicyNumber>
                <xsl:value-of select="strings[1]"/>
            </PolicyNumber>
            <CommissionFactorMultiplier>
                <xsl:value-of select="strings[2]"/>
            </CommissionFactorMultiplier>
            <PremiumValue>
                <xsl:value-of select="strings[3]"/>
            </PremiumValue>
            <SalesmanCommissionValue>
                <xsl:value-of select="strings[4]"/>
            </SalesmanCommissionValue>
            <ManagerCommissionValue>
                <xsl:value-of select="strings[5]"/>
            </ManagerCommissionValue>
            <GL_COR>
                <xsl:value-of select="strings[7]"/>
            </GL_COR>
            <GL_OPO>
                <xsl:value-of select="strings[8]"/>
            </GL_OPO>
        </CalculationOutput>
    </xsl:template>
</xsl:stylesheet>

Input:

<PricingResultsV6>     
    <subItems>
        <SubItem>   
            <profiles>
                <ProfileValues>
                    <values> 
                        <strings>800210</strings> 
                        <strings>THC</strings> 
                        <strings>10.0</strings> 
                        <strings>20.0</strings> 
                        <strings>30.0</strings> 
                        <strings>40.0</strings> 
                        <strings>550.0</strings> 
                        <strings>640.0</strings> 
                    </values>
                </ProfileValues>
            </profiles>
        </SubItem>
    </subItems>
</PricingResultsV6>

Output:

<CalculationOutput>
    <PolicyNumber>
        800210
    </PolicyNumber>
    <CommissionFactorMultiplier>
        THC
    </CommissionFactorMultiplier>
    <PremiumValue>
        10.0
    </PremiumValue>
    <SalesmanCommissionValue>
        20.0
    </SalesmanCommissionValue>
    <ManagerCommissionValue>
        30.0
    </ManagerCommissionValue>
    <GL_COR>
        550.0
    </GL_COR>
    <GL_OPO>
        640.0
    </GL_OPO>
</CalculationOutput>

Upvotes: 2

Related Questions