1

This is my xml Document.

<w:document xmlns:w="w">
 <w:body>
   <w:p>
        <w:r>
           <w:t>
               Para1
            </w:t>
        </w:r>
     </w:p>
   <w:p>
        <w:r>
           <w:t>
               Para2
            </w:t>
        </w:r>
     </w:p>
   <w:p>
        <w:r>
           <w:t>
               Para3
            </w:t>
        </w:r>
     </w:p>
   <w:p>
        <w:r>
           <w:t>
               Para4
            </w:t>
        </w:r>
     </w:p>
   <w:p>
        <w:r>
           <w:t>
               Para5
            </w:t>
        </w:r>
     </w:p>

   <w:tbl>
         <w:tr>
            <w:tc>
               <w:p>
                  <w:r>
                    <w:t>
                         Para6
                    </w:t>
                   </w:r>
                </w:p>
              </w:tc>
            <w:tc>
               <w:p>
                  <w:r>
                    <w:t>
                         Para7 
                    </w:t>
                   </w:r>
                </w:p>
              </w:tc>
           </w:tr>
        </w:tbl>
     <w:p>
        <w:r>
           <w:t>
               Para8
            </w:t>
        </w:r>
     </w:p>
  <w:tbl>
         <w:tr>
            <w:tc>
               <w:p>
                  <w:r>
                    <w:t>
                         Para9
                    </w:t>
                   </w:r>
                </w:p>
              </w:tc>
            <w:tc>
               <w:p>
                  <w:r>
                    <w:t>
                         Para10
                    </w:t>
                   </w:r>
                </w:p>
              </w:tc>
           </w:tr>
        </w:tbl>
    <w:p>
        <w:r>
           <w:t>
               Para11
            </w:t>
        </w:r>
     </w:p>
</w:body>
</w:document>

Now, I want to increment my global variable whenever <w:tbl><w:tr> encounters.for my above xml file,it has two <w:tr> nodes inside <w:tbl>.

So, for example :  
                1. if my current node is Para8 then it's count will be 1.
                2. if my current node is para11 then it's count will be 2.
   

How i do it?

Saravanan
  • 11,372
  • 43
  • 143
  • 213
  • This post should anwser your question: [in-xslt-how-do-i-increment-a-global-variable-from-a-different-scope][1] [1]: http://stackoverflow.com/questions/833118/in-xslt-how-do-i-increment-a-global-variable-from-a-different-scope – Patrick Bédert Sep 28 '11 at 11:42

1 Answers1

2

XSLT is a functional language and in any functional language the value of a variable, one set, cannot be updated. One needs a "paradigm shift" -- to start thinking in a functional way -- in order to understand that the "capability" to update variables isn't necessary at all. For any imperative algorithm (that uses variable update) there is a corresponding functional algorithm (that doesn't require update of any variable).

There are a number of advantages using a functional programming style over an imperative one -- the main being that a functional program is much better to read, understand, maintain and even prove correct. Due to variables being immutable, the optimizer of a compiler can perform much more aggressive optimizations and this results in more efficient, highly optimized compiled programs.

In this particular case, it isn't necessary to update a variable in order to get the required count:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:w="w">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
     <xsl:for-each select=
      "//w:t
         [contains(., 'Para8')
         or
          contains(., 'Para11')
         ]
     ">
       <xsl:number level="any" count="w:tbl/w:tr"/>
       <xsl:text>&#xA;</xsl:text>
     </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

 <w:document xmlns:w="w">
    <w:body>
        <w:p>
            <w:r>
                <w:t>                Para1             </w:t>
            </w:r>
        </w:p>
        <w:p>
            <w:r>
                <w:t>                Para2             </w:t>
            </w:r>
        </w:p>
        <w:p>
            <w:r>
                <w:t>                Para3             </w:t>
            </w:r>
        </w:p>
        <w:p>
            <w:r>
                <w:t>                Para4             </w:t>
            </w:r>
        </w:p>
        <w:p>
            <w:r>
                <w:t>                Para5             </w:t>
            </w:r>
        </w:p>
        <w:tbl>
            <w:tr>
                <w:tc>
                    <w:p>
                        <w:r>
                            <w:t>                          Para6                     </w:t>
                        </w:r>
                    </w:p>
                </w:tc>
                <w:tc>
                    <w:p>
                        <w:r>
                            <w:t>                          Para7                      </w:t>
                        </w:r>
                    </w:p>
                </w:tc>
            </w:tr>
        </w:tbl>
        <w:p>
            <w:r>
                <w:t>                Para8             </w:t>
            </w:r>
        </w:p>
        <w:tbl>
            <w:tr>
                <w:tc>
                    <w:p>
                        <w:r>
                            <w:t>                          Para9                     </w:t>
                        </w:r>
                    </w:p>
                </w:tc>
                <w:tc>
                    <w:p>
                        <w:r>
                            <w:t>                          Para10                     </w:t>
                        </w:r>
                    </w:p>
                </w:tc>
            </w:tr>
        </w:tbl>
        <w:p>
            <w:r>
                <w:t>                Para11             </w:t>
            </w:r>
        </w:p>
    </w:body>
</w:document>

the wanted, correct result is produced:

1
2

In case this value should be contained in a variable -- to be used later somewhere in its scope, one will simply define the variable as:

 <xsl:variable name="vMyCount">
   <xsl:number level="any" count="w:tbl/w:tr"/>
 </xsl:variable>

And you can use this variable as in the transformation below:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:w="w">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
     <xsl:for-each select=
      "//w:t
         [contains(., 'Para5')
         or
          contains(., 'Para8')
         or
          contains(., 'Para11')
         ]
     ">
     <xsl:variable name="vMyCount">
       <xsl:number level="any" count="w:tbl/w:tr"/>
     </xsl:variable>
     <xsl:value-of select=
      "concat($vMyCount,
              substring('0', 1 + boolean(string($vMyCount)))
              )"/>
       <xsl:text>&#xA;</xsl:text>
     </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

producing the same correct result:

0
1
2
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • @_Dimitre Novatchev :It's working fine.But, for example if my current node is Para5 then it's count appeared as Nan.because, there is no encounted on that time.So, is this possible to return 0 on this new case? – Saravanan Sep 28 '11 at 12:54
  • @Saravanan: I need to read the spec on `` -- it is quite complicated. You could use an alternative: ` ' -- this works OK. – Dimitre Novatchev Sep 28 '11 at 13:08
  • @_Dimitre Novatchev:it is working for the new case Para5 but not above said old cases.Actually, it is not counting on old cases.Is there any way to check vMyCount is a number or not? – Saravanan Sep 28 '11 at 13:23
  • @Saravan: What do you mean by "old cases" ? – Dimitre Novatchev Sep 28 '11 at 13:47
  • @Saravan: My comment is correct. For your convenience and easy understanding I updated my answer (at the very end) -- the right answers for all cases are produced. – Dimitre Novatchev Sep 28 '11 at 13:51
  • @_Dimitre Novatchev:Sorry to say this.Para8 and Para9 having the value of vMyCount as 0 always.because, it might be wrong on my side.Please, let me go through my entire code and then tell you which is correct or not.Anyway thanks for your great support. – Saravanan Sep 28 '11 at 14:18
  • @Saravan: As you see the results of execution of my code, the produced values *are* correct. You need to look into your code and find the real problem. This specific SO question is fully answered and you may consider accepting it. – Dimitre Novatchev Sep 28 '11 at 14:32
  • @_Dimitre Novatchev:Yes, definitely.I am not delaying for this problem...I just told you..Now i will mark your answer... – Saravanan Sep 28 '11 at 15:31
  • @Saravan: You are welcome. Of course, you need to ask new questions about any other problems you experience. In doing so, try to define the problem most precisely, whith complete, but minimal XML, the exact result wanted and a precise explanation of the requirements for the transformation. – Dimitre Novatchev Sep 28 '11 at 15:56
  • @Saravan: I updated the solution to use `` and to produce `0` when the count is `0`. Seems that the XSLT 1.0 spec isn't very definite about the required behavior in the 0-case and different XSLT 1.0 processors have implemented their own behavior. – Dimitre Novatchev Sep 28 '11 at 19:21