XML to XML transformation using XSL.

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • shakilalig
    New Member
    • Sep 2008
    • 4

    #1

    XML to XML transformation using XSL.

    Hi All,

    I am writing an XSL to transform the XML to XML.Only change i need in xml is to add the value for the price element
    under book tag for which publisher location is "World".
    The value for the price tag should be the sum of the value of price tag of two book tags (location for one is US and location of other is India).

    here is the snippets from the code:

    Code:
    book.xml
    		---------------------------------------------------
    
    		<?xml version="1.0" encoding="ISO-8859-1"?>
    <?xml-stylesheet type="text/xsl" href="test.xsl"?>
    <booklist>
    <book>
    	<publisher>
    		<location>India</location>
    		<identity id="111">book.com</identity>
    	</publisher>
    <title>bookname1</title>
    <price>80</price>
    
    </book>
    
    
    
    <book>
    	<publisher>
    		<location>US</location>
    		<identity id="222">usbook.com</identity>
    	</publisher>
    <title>bookname2</title>
    <price>60</price>
    
    </book>
    
    <book>
    	<publisher>
    		<location>UK</location>
    		<identity id="333">ukbook.com</identity>
    	</publisher>
    <title>bookname3</title>
    <price>50</price>
    
    </book>
    
    <book>
    	<publisher>
    		<location>Singapore</location>
    		<identity id="444">sgbook.com</identity>
    	</publisher>
    <title>bookname4</title>
    <price>50</price>
    
    </book>
    
    
    <book>
    	<publisher>
    		<location>World</location>
    		<identity id="000">worldbook.com</identity>
    	</publisher>
    <title>bookname5</title>
    <price></price>
    
    </book>
    </booklist>
    
    
    
    ---------------------------------------------------
    Code:
    ----------------book.xsl--------------------------
    
    <?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" media-type="text/xml" omit-xml-declaration="yes" version="1.0" />
    
    <xsl:template match="/ | @* | node()">
    <xsl:copy>
    <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
    </xsl:template>
     
    <xsl:template match="bookList/book" >
    
      
    	<xsl:copy>
    		<xsl:apply-templates select="@* | node()"/>
    			
    			<xsl:if test="(publisher/location = 'India')"> 
    			<xsl:if test="(publisher/identity[@id] = '111')"> 
    				 <xsl:variable name="A1SoloTotal"><xsl:value-of select="//booklist/book/price"/></xsl:variable>
    			</xsl:if> 
    			</xsl:if> 
    
    			<xsl:if test="(publisher/location = 'US')"> 
    			<xsl:if test="(publisher/identity[@id] = '222')"> 
    				 <xsl:variable name="A2SoloTotal"><xsl:value-of select="//booklist/book/price"/></xsl:variable>
    			</xsl:if> 
    			</xsl:if> 
    
    			<xsl:if test="(publisher/location = 'World')"> 
    			<xsl:if test="(publisher/identity[@id] = '000')"> 
    				 <price><xsl:value-of select='$A1SoloTotal'+'$A2SoloTotal'/></price>
    			</xsl:if> 
    			</xsl:if> 
    		
    	</xsl:copy>
       
    </xsl:template>
    
    </xsl:stylesheet>






    please get back to me today if you can help in any way.

    thanks

    Shakil
  • Dormilich
    Recognized Expert Expert
    • Aug 2008
    • 8694

    #2
    what exactly is your problem? at the first glance I don't see a mistake in the code (well, I had no time testing yet)
    except one writing mistake, 'booklist/book' (template) and the value-of XPath (you're already starting at book, therefore: "price" (not "//booklist/book/price")

    when I understand it right, you want: price(world) = price(US) + price(India) ? do you have in <booklist> only one book of US and India? or are there other constraints too?

    regards

    Comment

    • shakilalig
      New Member
      • Sep 2008
      • 4

      #3
      Originally posted by Dormilich
      what exactly is your problem? at the first glance I don't see a mistake in the code (well, I had no time testing yet)
      except one writing mistake, 'booklist/book' (template) and the value-of XPath (you're already starting at book, therefore: "price" (not "//booklist/book/price")

      when I understand it right, you want: price(world) = price(US) + price(India) ? do you have in <booklist> only one book of US and India? or are there other constraints too?

      regards
      ----------------------------------------------------------------------------------------------------------------
      Thanks for your review.
      The issue is with the declaration of variable The variable is not getting accessible in the clause where we are looking for the sum.

      price(world) = price(US) + price(India) ? this is right

      <xsl:if test="(publishe r/location = 'World')">
      <xsl:if test="(publishe r/identity[@id] = '000')">
      <price><xsl:val ue-of select='$A1SoloTotal' + '$A2SoloTotal' /></price>
      </xsl:if>
      </xsl:if>

      For first price Constraint is that the location should be US and id=222 .
      For second price Constraint is that the location should be India and id=111.

      Those two should go as the sum for the book tag having location World and id="000"
      I hope it clears the issue?

      The first issue is getting access to variable declared in different if clauses.


      The other is how to put this as the sum for an element with blank text value?

      Comment

      • Dormilich
        Recognized Expert Expert
        • Aug 2008
        • 8694

        #4
        XML to XML transformation using XSL

        after a bit of testing, I came to the conclusion that all XPath expressions were somehow screwed up.
        Originally posted by shakilalig
        [CODE=xsl]----------------book.xsl--------------------------

        <?xml version="1.0" encoding="UTF-8"?>
        <xsl:styleshe et version="1.0" xmlns:xsl="http ://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" media-type="text/xml" omit-xml-declaration="ye s" version="1.0" />

        <xsl:template match="/ | @* | node()">
        <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
        </xsl:template>

        <xsl:template match="bookList/book" >
        <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
        <xsl:if test="(publishe r/location = 'India')">
        <xsl:if test="(publishe r/identity[@id] = '111')">
        <xsl:variable name="A1SoloTot al"><xsl:valu e-of select="//booklist/book/price"/></xsl:variable>
        </xsl:if>
        </xsl:if>

        <xsl:if test="(publishe r/location = 'US')">
        <xsl:if test="(publishe r/identity[@id] = '222')">
        <xsl:variable name="A2SoloTot al"><xsl:valu e-of select="//booklist/book/price"/></xsl:variable>
        </xsl:if>
        </xsl:if>

        <xsl:if test="(publishe r/location = 'World')">
        <xsl:if test="(publishe r/identity[@id] = '000')">
        <price><xsl:val ue-of select='$A1Solo Total'+'$A2Solo Total'/></price>
        </xsl:if>
        </xsl:if>
        </xsl:copy>
        </xsl:template>

        </xsl:stylesheet>[/CODE]
        I left out the xsl:copy because I didn't know what exactly you want to copy (so I concentrated on the 'world' issue), still
        - why defining xsl:copy twice (inside and outside the second template)?
        - if you want to copy a node without making any changes consider xsl:copy-of

        getting the world value:
        - the xsl:template and xsl:apply-templates XPath looped for every book element, changed that to loop for every booklist (for the sole computation this was easier to start with)
        - the xsl:variable's XPath returned a node-set: //booklist/book/price are all price elements (in your case), changed that to price (book/price respectivly, since I loop now for booklist), which is now relatively declared and thus a single node (resp. its string-value).
        - I dropped the xsl:if conditions in favour of one XPath expression in xsl:variable using select attribute
        - shortened the 'world' xsl:if to one condition (there's no need of two xsl:ifs)
        - the syntax of the computation is wrong (missing quotation marks)

        so finally I came up with
        [CODE=xsl]<xsl:template match="/">
        <xsl:apply-templates />
        </xsl:template>

        <xsl:template match="booklist ">
        <xsl:variable name="A1SoloTot al" select="book/price[../descendant::loc ation = 'India'][../descendant::ide ntity/@id = '111']"/>
        <xsl:variable name="A2SoloTot al" select="book/price[../descendant::loc ation = 'US'][../descendant::ide ntity/@id = '222']"/>
        <xsl:if test="book/price[../descendant::loc ation = 'World'][../descendant::ide ntity/@id = '000']">
        <price><xsl:val ue-of select="$A1Solo Total + $A2SoloTotal"/></price>
        </xsl:if>
        </xsl:template>[/CODE]
        there is still room for improvement (we could even make a parameter-dependent template.... depending on the file).

        In the copy case I guess you want to copy the whole xml file with the value for 'World' inserted... there may be adaptions necessary. And I can probably think of a more elegant copy cycle, but this depends on the xml file.

        regards
        Last edited by Dormilich; Sep 12 '08, 08:41 AM. Reason: always those writing mistakes....

        Comment

        • Dormilich
          Recognized Expert Expert
          • Aug 2008
          • 8694

          #5
          XML to XML transformation using XSL

          oops, missed your first reply while posting #4

          Originally posted by shakilalig
          The issue is with the declaration of variable The variable is not getting accessible in the clause where we are looking for the sum.

          Code:
          <xsl:if test="(publisher/location = 'World')"> 
          	<xsl:if test="(publisher/identity[@id] = '000')"> 
          		 <price><xsl:value-of select=[b]'$A1SoloTotal' + '$A2SoloTotal' [/b] /></price>
          	</xsl:if> 
          </xsl:if>
          this is because there's a syntax error. it is
          Code:
          // either
          <xsl:value-of select=[b]"[/b]'$A1SoloTotal' + '$A2SoloTotal'[b]"[/b] />
          // which would probably return the values as string
          // or
          <xsl:value-of select=[b]'[/b]$A1SoloTotal + $A2SoloTotal[b]'[/b]  />
          // this should do the computation
          Originally posted by shakilalig
          The other is how to put this as the sum for an element with blank text value?
          I would rather create the whole world-book element in the xsl, then you could loop without condition and copy all book elements
          Code:
          <xsl:copy-of select="book" />
          but there wouldn't be a problem in adding conditions, though.

          for the computation, see my previous post

          regards

          PS: please use [code] tags when posting code
          Last edited by Dormilich; Sep 12 '08, 08:30 AM. Reason: added [code] tag info

          Comment

          • shakilalig
            New Member
            • Sep 2008
            • 4

            #6
            HI Dormilich,
            While i was trying to put your idea to my other xml using the xsl , it didn't produce the desired result.
            It converted to just the same original XML file. The transformed xml didn't have the added value.
            It seems i had made a mistake somewhere . Please advise the change required.
            I am stuck for three days.

            issue:
            abc:TotalMortga gesPrincipalAmo unt Element in the third group should be the sum of MortgagesPrinci palAmount in group 1 and group 2.
            group 1 where numericContext@ id = numericABCLevel _1
            group 2 where numericContext@ id = numericABCLevel _2


            Code:
            ****************************CODE*************************************************
            [U]test.xml[/U]
            
            <?xml version="1.0" encoding="UTF-8"?>
            <group xmlns="http://www.xbrl.org/2001/instance" xmlns:abc="http://www.abc.com/2001-11-05"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >[INDENT]<group>[INDENT]<numericContext cwa="false" id="numericABCLevel_1" precision="18">
            <entity>
            <identifier scheme="">88004325080</identifier>
            </entity>
            </numericContext>[/INDENT][INDENT]<abc:CapitalAmount numericContext="numericABCLevel_1">0.0</abc:CapitalAmount>
            <abc:PrincipalAmount numericContext="numericABCLevel_1">1445678366.64</abc:PrincipalAmount>
            <abc:RiskWeight numericContext="numericABCLevel_1"/>
            <abc:WeightedAmount numericContext="numericABCLevel_1"/>
            
            <abc:MortgagesPrincipalAmount numericContext="numericABCLevel_1">7.85</abc:MortgagesPrincipalAmount>[/INDENT]
            </group>[/INDENT][list][/list][INDENT]
            <group>[INDENT]<numericContext  id="numericABCLevel_2" precision="18">
            <entity>
            <identifier scheme="">88004325081</identifier>
            </entity>
            </numericContext>[/INDENT]
            [INDENT]<abc:CapitalAmount numericContext="numericABCLevel_2">0.0</abc:CapitalAmount>
            <abc:PrincipalAmount numericContext="numericABCLevel_2">2445678366.64</abc:PrincipalAmount>
            <abc:RiskWeight numericContext="numericABCLevel_2"/>
            <abc:WeightedAmount numericContext="numericABCLevel_2"/>
            
            <abc:MortgagesPrincipalAmount numericContext="numericABCLevel_2">8.85</abc:MortgagesPrincipalAmount>[/INDENT]
            </group>[/INDENT][INDENT]<group>[INDENT]<numericContext  id="numericABCLevel_0" precision="18">
            <entity>
            <identifier scheme="">88004325081</identifier>
            </entity>
            </numericContext>[/INDENT]
            [INDENT]<abc:TotalCapitalAmount numericContext="numericABCLevel_0"></abc:CapitalAmount>
            <abc:TotalPrincipalAmount numericContext="numericABCLevel_0"></abc:PrincipalAmount>
            <abc:TotalRiskWeight numericContext="numericABCLevel_0"/>
            <abc:TotalWeightedAmount numericContext="numericABCLevel_0"/>
            
            <abc:TotalMortgagesPrincipalAmount numericContext="numericABCLevel_0"></abc:MortgagesPrincipalAmount>[/INDENT]</group>[/INDENT]</group>
            
            *************************************************************************
            [U]test.xsl[/U]
            
            <?xml version="1.0" encoding="UTF-8"?>
            <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.xbrl.org/2001/instance" xmlns:abc="http://www.apra.gov.au/statistics/xbrl/2001-11-05"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
            <xsl:output method="xml" media-type="text/xml" omit-xml-declaration="yes" version="1.0" indent="yes"/>
            <xsl:strip-space elements="*"/>
            
            <xsl:template match="/ | @* | node()">
            <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
            </xsl:copy>
            </xsl:template>
            
            <xsl:template match="group"> 
              
                <xsl:variable name="A1SoloTotal" select="group/abc:MortgagesPrincipalAmount[../descendant::numericContext/@id = 'numericABCLevel_1']"/>
            
                <xsl:variable name="A2SoloTotal" select="group/abc:MortgagesPrincipalAmount[../descendant::numericContext/@id = 'numericABCLevel_2']"/>
               
                <xsl:if test="group/abc:TotalMortgagesPrincipalAmount[../descendant::numericContext/@id = 'numericABCLevel_0']">
            	 <abc:TotalMortgagesPrincipalAmount><xsl:value-of select="$A1SoloTotal + $A2SoloTotal"/></abc:TotalMortgagesPrincipalAmount>
            	
                </xsl:if>
            
            </xsl:template> 
            
            
            </xsl:stylesheet>
             
            
            *********************************************************************************
            Desired Result
            
            <?xml version="1.0" encoding="UTF-8"?>
            <group xmlns="http://www.xbrl.org/2001/instance" xmlns:abc="http://www.abc.com/2001-11-05"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
            <group>
            <numericContext cwa="false" id="numericABCLevel_1" precision="18">
            <entity>
            <identifier scheme="">88004325080</identifier>
            </entity>
            </numericContext>
            
            <abc:CapitalAmount numericContext="numericABCLevel_1">0.0</abc:CapitalAmount>
            <abc:PrincipalAmount numericContext="numericABCLevel_1">1445678366.64</abc:PrincipalAmount>
            <abc:RiskWeight numericContext="numericABCLevel_1"/>
            <abc:WeightedAmount numericContext="numericABCLevel_1"/>
            
            <abc:MortgagesPrincipalAmount numericContext="numericABCLevel_1">7.855722136E9</abc:MortgagesPrincipalAmount>
            </group>
            
            <group>
            <numericContext  id="numericABCLevel_2" precision="18">
            <entity>
            <identifier scheme="">88004325081</identifier>
            </entity>
            </numericContext>
            
            <abc:CapitalAmount numericContext="numericABCLevel_2">0.0</abc:CapitalAmount>
            <abc:PrincipalAmount numericContext="numericABCLevel_2">2445678366.64</abc:PrincipalAmount>
            <abc:RiskWeight numericContext="numericABCLevel_2"/>
            <abc:WeightedAmount numericContext="numericABCLevel_2"/>
            
            <abc:MortgagesPrincipalAmount numericContext="numericABCLevel_2">7.855722136E9</abc:MortgagesPrincipalAmount>
            </group>
            
            <group>
            <numericContext  id="numericABCLevel_0" precision="18">
            <entity>
            <identifier scheme="">88004325081</identifier>
            </entity>
            </numericContext>
            
            <abc:TotalCapitalAmount numericContext="numericABCLevel_0"></abc:CapitalAmount>
            <abc:TotalPrincipalAmount numericContext="numericABCLevel_0"></abc:PrincipalAmount>
            <abc:TotalRiskWeight numericContext="numericABCLevel_0"/>
            <abc:TotalWeightedAmount numericContext="numericABCLevel_0"/>
            
            <abc:TotalMortgagesPrincipalAmount numericContext="numericABCLevel_0">16.7</abc:MortgagesPrincipalAmount>
            </group>
            </group>
            
            
            *****************************************************************************
            Originally posted by Dormilich
            oops, missed your first reply while posting #4


            this is because there's a syntax error. it is
            Code:
            // either
            <xsl:value-of select=[b]"[/b]'$A1SoloTotal' + '$A2SoloTotal'[b]"[/b] />
            // which would probably return the values as string
            // or
            <xsl:value-of select=[b]'[/b]$A1SoloTotal + $A2SoloTotal[b]'[/b]  />
            // this should do the computation
            I would rather create the whole world-book element in the xsl, then you could loop without condition and copy all book elements
            Code:
            <xsl:copy-of select="book" />
            but there wouldn't be a problem in adding conditions, though.

            for the computation, see my previous post

            regards

            PS: please use [code] tags when posting code

            Comment

            • Dormilich
              Recognized Expert Expert
              • Aug 2008
              • 8694

              #7
              Originally posted by shakilalig
              HI Dormilich,
              While i was trying to put your idea to my other xml using the xsl , it didn't produce the desired result.
              It converted to just the same original XML file. The transformed xml didn't have the added value.
              It seems i had made a mistake somewhere . Please advise the change required.
              I am stuck for three days.
              problem 1: you don't use [code] tags (this makes the code hard to read)
              problem 2: you already copy all the nodes in the first template
              problem 3: I'm just before going home, I'll look into it tomorrow

              regards

              Comment

              • shakilalig
                New Member
                • Sep 2008
                • 4

                #8
                Originally posted by Dormilich
                problem 1: you don't use [code] tags (this makes the code hard to read)
                problem 2: you already copy all the nodes in the first template
                problem 3: I'm just before going home, I'll look into it tomorrow

                regards
                Sorry Dormilich, I missed to put the Code tag in other two files. I had put in the first one. Please look into it and advise the remedy.

                Comment

                • Dormilich
                  Recognized Expert Expert
                  • Aug 2008
                  • 8694

                  #9
                  geez, that was givin me the creeps....

                  problem 1: have a look at your xml, it's not well-formed (though that's a minor problem and easily fixed)

                  problem2: <xsl:copy-of> didn't work.... until I inserted an additional namespace prefix with the default namespace

                  note: I'd rename the root node to prevent confusions

                  solution principle

                  [CODE=xsl]// this is not valid code!
                  <xsl:template match="/">
                  &#160; <xsl:copy-of/> // all nodes except numericABCLevel _0
                  &#160; <xsl:call-template/> // numericABCLevel _0
                  </xsl:template>

                  <xsl:template >
                  &#160; <xsl:copy-of/> // all nodes except TotalMortgagesP rincipalAmount
                  &#160; <xsl:value-of/> // TotalMortgagesP rincipalAmount
                  </xsl:template>[/CODE]
                  if you want to try a bit for yourself, this is the "header" I used (you need not sticking with 'inp' as prefix, choose one to your liking):
                  Code:
                  <xsl:stylesheet version="1.0" 
                  &#160;  xmlns="http://www.xbrl.org/2001/instance" 
                  &#160;  xmlns:inp="http://www.xbrl.org/2001/instance" 
                  &#160;  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                  &#160;  xmlns:abc="http://www.apra.gov.au/statistics/xbrl/2001-11-05" 
                  &#160;  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
                  
                  //inp:group <!-- these are the group elements now -->
                  note: I somehow had problems getting the values

                  full solution in the next post, because I'll be on vacation for a week

                  regards

                  Comment

                  • Dormilich
                    Recognized Expert Expert
                    • Aug 2008
                    • 8694

                    #10
                    please use this solution only when you have problems with the code (well, at least try, ok?)

                    note: maybe some of the XPaths can be simplified in your environment
                    [CODE=xsl]<?xml version="1.0" encoding="UTF-8"?>
                    <xsl:styleshe et version="1.0"
                    xmlns="http://www.xbrl.org/2001/instance"
                    xmlns:inp="http ://www.xbrl.org/2001/instance"
                    xmlns:xsl="http ://www.w3.org/1999/XSL/Transform"
                    xmlns:abc="http ://www.apra.gov.au/statistics/xbrl/2001-11-05"
                    xmlns:xsi="http ://www.w3.org/2001/XMLSchema-instance" >
                    <xsl:output method="xml" indent="yes"/>

                    <xsl:template match="/">
                    <group>
                    <xsl:copy-of select="//inp:group[descendant::inp :numericContext/@id != 'numericABCLeve l_0']" />
                    <xsl:call-template name="g1" />
                    </group>
                    </xsl:template>

                    <xsl:template name="g1">
                    <xsl:variable name="A1SoloTot al" select="//inp:group/*[name() = 'abc:MortgagesP rincipalAmount'][@numericContext = 'numericABCLeve l_1']"/>
                    <xsl:variable name="A2SoloTot al" select="//inp:group/*[name() = 'abc:MortgagesP rincipalAmount'][@numericContext = 'numericABCLeve l_2']"/>
                    <group>
                    <xsl:copy-of select="//inp:group/*[local-name() != 'TotalMortgages PrincipalAmount '][../inp:numericCont ext/@id = 'numericABCLeve l_0']"/>
                    <abc:TotalMortg agesPrincipalAm ount><xsl:value-of select="$A1Solo Total + $A2SoloTotal"/></abc:TotalMortga gesPrincipalAmo unt>
                    </group>
                    </xsl:template>

                    </xsl:stylesheet>[/CODE]

                    Comment

                    Working...