如何使用xslt 2.0读取我的特定标签时增加全局变量?

时间:2011-09-28 11:22:23

标签: xml xslt xpath

这是我的xml文档。

<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>

现在,我想在<w:tbl><w:tr>遇到我的全局变量时递增。对于我上面的xml文件,它在<w:tr>内有两个<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.
   

我是怎么做到的?

1 个答案:

答案 0 :(得分:2)

XSLT是一种函数式语言,在任何函数式语言中,变量(一组)的值都无法更新。人们需要一种“范式转换” - 开始以功能性方式思考 - 以便理解根本不需要更新变量的“能力”。对于任何命令式算法(使用变量更新),都有相应的功能算法(不需要更新任何变量)。

使用函数式编程风格而不是命令式编程风格有许多优点 - 主要是功能性程序更好地阅读,理解,维护甚至证明是正确的。由于变量是不可变的,编译器的优化器可以执行更积极的优化,从而产生更高效,高度优化的编译程序。

在这种特殊情况下,没有必要更新变量以获得所需的计数

<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>

在提供的XML文档上应用此转换时

 <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>

产生了想要的正确结果

1
2

如果此值应包含在变量中 - 稍后在其范围内某处使用,则只需将变量定义为

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

您可以在下面的转换中使用此变量

<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>

产生相同的正确结果

0
1
2