XSLT 的几个问题的讨论

看到好多资料和书讲述XSLT,都是泛泛而论,该讨论清楚的问题都没讨论。真是失望。所以所有的书都差不多,也就不奇怪了。
    
    
还是先讨论几个重要的问题吧!(一家之言,欢迎讨论。。)
    
    
 
   
   
1, 上下文节点是当前节点吗?
   
   
上下文节点当然不是当前节点,上下文节点用“.”来表示,而当前节点则是用current()函数来获得的。请看实例:
    
    
XML 文件:
   
   
<root>
   
   
<AAA  name=first>
   
   
       <BBB name=first>
   
   
          <CCC>hello world!!</CCC>
   
   
       </BBB>
   
   
</AAA>

   
   
    
    
<AAA name=second>
       <BBB name=first>
          <CCC>OK WELCOME!!</CCC>
       </BBB>
</AAA>
</root>
   
   
XSL 文件 :
   
   
<?xml version="1.0"?>
  
  
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  
  
    <xsl:template match="AAA">
  
  
        <hr/>
  
  
            <table border="1"> 
  
  
            <tr> 
  
  
               <td> 
  
  
              <xsl:value-of  select="./BBB/CCC"/>
  
  
           </td>
  
  
           <td>
  
  
                <xsl:value-of  select="current()/BBB/CCC"/>
  
  
             </td>   
  
  
        </tr>
  
  
           <td>
  
  
              <xsl:value-of select="BBB[./@name='first']/CCC"/>
  
  
           </td>
  
  
           <td>   
  
  
             <xsl:value-of select="BBB[current()/@name='first']/CCC"/>
  
  
           </td>  
  
  
        </table>
  
  
    </xsl:template>
  
  
</xsl:stylesheet>
  
  
转换之后的网页变成了:
   
   

    
     
     
     
 
    
    

     
       
      
      
  
      
      
  
      
      
  
    
    
   
   
   
   
    
    

   
   
   
   
很容易看出来了吧,第一个表格,也就是第一个AAA元素的输出,很明显上下文节点和当前节点没有任何区别。
    
    
但是第二个节点呢,最后一行的CCC没有输出来,我们来看XSL代码:
    
    
           <td>
  
  
              <xsl:value-of select="BBB[./@name='first']/CCC"/>
  
  
           </td>
  
  
           <td>   
  
  
             <xsl:value-of select="BBB[current()/@name='first']/CCC"/>
  
  
           </td>  
  
  
最后一行第一列,把CCC的内容输出来了,BBB的约束条件为上下文节点的属性name的值为first,这证明,上下文节点,指的是BBB;而第二列呢,CCC的内容没有输出来,我们知道此时的当前节点是AAA,而AAA的name属性为second,所以往往上下文节点处在中括号中的时候,它就不是上下文节点了。
    
    
其实,我们在编写代码的时候,一旦涉及到Xpath表达式,相对路径总有一个缺省的./,我们也很少把代码写成:“<xsl:value-of select="BBB[./@name='first']/CCC"/>” ,而是写成了:“<xsl:value-of select="BBB[@name='first']/CCC"/>”。它的实际意思,其实应该是:“<xsl:value-of select="./BBB[./@name='first']/CCC"/>”。
    
    
现在给上下文节点下一个比较明确的定义:XPath表达式中,.所处的两个/之间的那个XML节点。
    
    
太晚了,明天接着讨论以下问题。
    
    
2,,<xsl:variable>的值和结果树片段问题。
   
   
3,<xsl:if  test=expression>中的expression不简单。
   
   
4,从XSL文件的处理过程来讨论:内嵌模板和经典的递归调用模板。
   
   
 
   
   
2,<xsl:variable>的值和结果树片段问题。 
  
  
    XML实例
<?xml version=1.0?>
   
   
<people>
  
  
	<person>
  
  
                       <name>张三</name>
  
  
                       <age>20</age>
  
  
       </person>
  
  
       <person>
  
  
               <name>李四</name>
  
  
               <age>21</age>
  
  
       </person>
  
  
      <person>
  
  
               <name>王五</name>
  
  
               <age>22</age>
  
  
      </person>
  
  
</people>
  
  
XSLT实例1(select赋值):
   
   
<?xml version=1.0?>
   
   
<xsl;:stylesheet xmlns:xsl=http://www.w3.org/1999/XSL/Transform>
   
   
<xsl:variable  name=nodeIdselect=2/>
   
   
<xsl:template match=people>
   
   
<xsl:copy-of select=person[$nodeId]/>
   
   
</xsl:template>
   
   
</xsl:stylesheet>
   
   
经转换后的结果为 :
    
    
<person>
  
  
               <name>李四</name>
  
  
               <age>21</age>
  
  
</person>
  
  
得到第二个节点没问题。
    
    
同样的XML文件
    
    
XSLT实例2(结果树片段):
   
   
<?xml version=1.0?>
   
   
<xsl;:stylesheet xmlns:xsl=http://www.w3.org/1999/XSL/Transform>
   
   
<xsl:variable  name=nodeId >2</xsl:variable>
   
   
<xsl:template match=people>
   
   
<xsl:copy-of select=person[$nodeId]/>
   
   
</xsl:template>
   
   
</xsl:stylesheet>
   
   
得到的结果为:
    
    
<person>
  
  
                       <name>张三</name>
  
  
                       <age>20</age>
  
  
</person>
  
  
<person>
  
  
               <name>李四</name>
  
  
               <age>21</age>
  
  
</person>
  
  
<person>
  
  
               <name>王五</name>
  
  
               <age>22</age>
  
  
</person>
  
  
把所有节点都输出来了。
    
    
也就是说person的限制条件变成了一个结果树片段,而该结果树片段一旦创建就总会存在,所以所有XML节点的限制条件都为真,可以理解。
    
    
网上有些人说输出的结果是第一个节点,也就是:
    
    
<person>
  
  
                       <name>张三</name>
  
  
                       <age>20</age>
  
  
</person>
  
  
也对,在linux操作系统中的结果的确如此,但是很难从语法上解释为什么会得到这样的结果。
    
    
注:我用的是eclipse+xmlbuddy的xml-apis.jar,经JAVA程序转换后的结果。
    
    
想利用结果树片段得到第二个片段也不难,
    
    
<xsl:copy-of select=person[postion()=$nodeId]/>
   
   
另外,结果树片段如下
    
    
<xsl:variable name=nodeId>
   
   
        <A>1</A>
   
   
        <B>3</B>
   
   
</xsl:variable>
   
   
如果使用<xsl:copy-of select=person[postion()=$nodeId]/>
   
   
则得到第13个节点(当然上例中没有第13个person),也就是说在比较时,参与比较的是结果树片段的value-of (所有文本节点的组合)。
    
    
 
   
   
3,<xsl:if  test=expression>中的expression不简单。
   
   
Expression可指定为逻辑表达式,很好理解,看下面的例子:
   
   
XML文件:
   
   
<tree>
   
   
   <branch size=0.5>可用作家具</branch>
   
   
   <branch>可用作建筑</branch>
   
   
   <branch color=yellow>可用作燃料</branch>
   
   
</tree>
   
   
XSLT文件:
   
   
<xsl:stylesheet version=1.0 xmlns:xsl=http://www.w3.org/1999/XSL/Transform>
   
   
        <xsl:template match=tree>
   
   
               <xsl:for-each select=branch>
   
   
                       <xsl:if test=@size>
   
   
                               <xsl:value-of select=./>
   
   
                       </xsl:if>
   
   
               </xsl:for-each>
   
   
        </xsl:for-each>
   
   
</xsl:stylesheet>
   
   
转换后的结果为:
    
    
 
   
   
可用作家具
    
    
 
   
   
从上面的例子看得出,test的值为一个属性,通过什么来判断真假呢?属性的值?
    
    
其实不是,在这里我们应该理解为:名为size的属性节点,是否存在.
    
    
如果存在,执行if 语句,否则不执行.
    
    
当然test的值,还可以是节点,
    
    
 
   
   
从另外一个角度来看这个问题:
    
    
XML文件:
   
   
<tree>
   
   
    <branch size=0.5>可用作家具</branch>
   
   
   <branch>可用作建筑</branch>
   
   
   <branch color=yellow>可用作燃料</branch>
   
   
</tree>
   
   
XSLT文件 :
   
   
<xsl:stylesheet xmlns:xsl=http://www.w3.org/1999/XSL/Transform>
   
   
        <xsl:template match=tree>
   
   
               <xsl:for-each select=branch>
   
   
                       <xsl:value-of select=not(@size)/>
   
   
               </xsl: for-each>
   
   
        </xsl:template>
   
   
</xsl:stylesheet>
   
   
结果输出什么:
    
    
实际输出结果为:false true true
    
    
OK,现在可以看到了,如果一个节点用于逻辑运算,则表示这样的节点时候存在,而并不是以节点的值来参与运算的.
   
   
 
   
   
4,从XSL文件的处理过程来讨论:内嵌模板和经典的递归调用模板。
   
   
        应用于元素节点和根节点的内嵌模板规则如下所示。 
  
  
<xsl:template match="*|/">
   
   
	<xsl:apply-templates/>
   
   
</xsl:template> 
   
   
  有的教程说<xsl:appy-templates/>未指定任何应用模板对象,就是应用上下文节点的所有子节点模板,这个说法,我个人认为该说法存在问题,应该说,应用上下文节点的所有除属性节点外的所有子结点。这样说的根据接下来说明。
   
   
应用于文本节点和属性节点的内嵌模板规则如下所示。 
   
   
<xsl:template match="text()|@*">
   
   
	<xsl:value-of select="."/>
   
   
</xsl:template>
   
   
也就是说对于文本节点和属性节点内嵌模板是输出节点的值。
    
    
看一个例子:
    
    
XML文件
   
   
<?xml version=1.0?>
   
   
<person>
   
   
        <name>张三</name>
   
   
        <age>20</age>
   
   
        <address>
   
   
            <state continent=Asia>中国</state>
   
   
               <province>广东</province>
   
   
               <city>珠海</city>
   
   
        </address>
   
   
</person>
   
   
XSL文件:
   
   
<xsl:stylesheet version=1.0 xmlns:xsl=http://www.w3.org/1999/XSL/Transform>
   
   
</xsl:stylesheet>
   
   
除了声明样式表外,什么语句都没有,那会输出什么呢?
    
    
结果:
张三
    
    
20
   
   
中国
    
    
广东
    
    
珠海
    
    
OK,现在看一下,XSLT的处理过程:
   
   
无论何时都是从根节点开始,也就是从 / 开始。/没有定义模板,应用内嵌模板规则,该规则应用所有子结点的模板,于是找到了“person”,但是“person”也没有定义,于是应用内嵌模板规则,规则是应用所有子节点的模板,于是找到了name,age,address,这三个都没有定义模板,于是应用默认模板规则,找到了它们各自的子节点,注意,最终的输出结果中,并没有“Asia”字样,也就是说state节点的<xsl:apply-templates/>并未应用属性“continent”的模板,否则,肯定会把“Aisa”字样输出来的 。
    
    
这就是我为什么说,“所有的子节点”所代表的,不包括属性子节点了。
    
    
好了,现在来看递归拷贝这个时常出现的家伙。
    
    
若需要递归地复制所有节点,可以使用如下的模板规则。 
   
   
<xsl:template match="@*|node()">
   
   
<xsl:copy>
   
   
<xsl:apply-templates select="@*|node()"/>
   
   
</xsl:copy>
   
   
</xsl:template>
   
   
 
   
   
好了,这是覆盖了所有节点和属性的内嵌模板了。
    
    
首先声明<xsl:copy>的作用,<xsl:copy>是拷贝当前节点,说直观一点,它只输出这样一个东西<AAA></AAA>,而不管原XML文件中<AAA>节点有多少属性,多少子节点,多么复杂。
    
    
按照从根节点开始的理论,根节点拷贝自身,然后应用子节点的模板,子节点的模板也是拷贝自身,然后应用它的子节点的模板。直到拷贝完所有节点。
    
    
很容易理解哈,但是,这是递归?
    
    
我到觉得,这没什么好递归的,只是所有的节点都定义好了,一个接一个的去处理了而已。
    
    
我们何妨将上面XSL代码看做:
    
    
<xsl:template match=/>
   
   
        <xsl:copy>
   
   
               <xsl:apply-template select=@*|node()/>
   
   
        </xsl:copy>
   
   
</xsl:template>
   
   
<xsl:template match=person>
   
   
        <xsl:copy>
   
   
               <xsl:apply-template select=@*|node()/>
   
   
        </xsl:copy>
   
   
</xsl:template>
   
   
<xsl:template match=name>
   
   
        <xsl:copy>
   
   
               <xsl:apply-template select=@*|node()/>
   
   
        </xsl:copy>
   
   
</xsl:template>
   
   
<xsl:template match=age>
   
   
        <xsl:copy>
   
   
               <xsl:apply-template select=@*|node()/>
   
   
        </xsl:copy>
   
   
</xsl:template>
..............

   
   
    
    
<xsl:template match=@continent>
        <xsl:copy>
               <xsl:apply-template select=@*|node()/>
        </xsl:copy>
</xsl:template>
………………………等等
    
    
这样看,是否清晰了些。
    
    
说白了,还是从根节点开始,按照模板规则来处理而已嘛!
    
    
好了,如果再想到别的什么问题,再来继续添加。。。。呵呵
    
    
 
   
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值