XSLT 1.0使用<xsl:for-each>中的position()和<xsl:template> </xsl:template> </xsl:for-each>

时间:2014-01-31 00:48:12

标签: xml xslt xslt-1.0

我的理解是,<xsl:template /><xsl:for-each>的使用几乎可以达到相同的目的,<xsl:for-each >是一种“匿名内联模板”。< / p>

问题但是,考虑到以下情况,我认为使用<xsl:for-each>更合适。 请验证我的理解,或者是否有办法通过<xsl:template>来实现输出?

输入XML:

<?xml version="1.0" encoding="UTF-8"?>
<books>
    <book.child.1>
        <title>charithram</title>
        <author>sarika</author>
    </book.child.1>
    <book.child.2>
        <title>doublebell</title>
        <author>psudarsanan</author>
    </book.child.2>
</books>

预期输出:

<?xml version="1.0" encoding="UTF-8"?>
<books>
   <book id="book1">
      <title>charithram</title>
      <author>sarika</author>
   </book>
   <book id="book2">
      <title>doublebell</title>
      <author>psudarsanan</author>
   </book>
</books>

XSLT1 [使用<xsl:for-each >] - 这会提供预期的输出

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
 <xsl:template match="/">
        <newbooks>
            <xsl:for-each select="books/*">
            <newbook id="book{position()}"> 
                <title><xsl:value-of select="title" /></title>
                <author> <xsl:value-of select="author" /></author>
            </newbook>
          </xsl:for-each>
           </newbooks>
 </xsl:template>
</xsl:stylesheet>

XSLT2 [使用<xsl:template >]

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />    
 <xsl:template match="/">
    <newbooks>
              <xsl:apply-templates/>    
     </newbooks>
 </xsl:template>
 <xsl:template match="books/*" >
    <newbook id="book{position()}"> 
        <title><xsl:value-of select="title" /></title>
        <author> <xsl:value-of select="author" /></author>
    </newbook>
 </xsl:template>
</xsl:stylesheet>

这不会给出预期的输出,而是获得的输出是

<?xml version="1.0" encoding="UTF-8"?>
    <newbooks>
       <newbook id="book2">
          <title>charithram</title>
          <author>sarika</author>
       </newbook>
       <newbook id="book4">
          <title>doublebell</title>
          <author>psudarsanan</author>
       </newbook>
    </newbooks>

我能想到得到2和4的唯一原因可能是id节点在上下文中的位置。
position()函数返回选定节点集中上下文节点的位置”。根据此定义,它适用于for-each,因为上下文是每个<book>元素。但为什么它不适用于模板?

我也试过<xsl:number>,但无法按预期工作

 <xsl:template match="/">
        <newbooks>
                  <xsl:apply-templates/>    
         </newbooks>
     </xsl:template>
     <xsl:template match="books/*" >
        <newbook >
            <xsl:attribute name="id">
              <xsl:text>book</xsl:text><xsl:number/>
            </xsl:attribute>
            <title><xsl:value-of select="title" /></title>
            <author> <xsl:value-of select="author" /></author>
        </newbook>
     </xsl:template>

我得到book1的输出,book1 [不递增]

请帮忙。

注意:我使用XSLT转换为输出XML,与输入XML相比,它具有完全不同的标记集,因此我不使用模板进行复制。

1 个答案:

答案 0 :(得分:1)

我认为您对这些差异的理解有点不对,但这不是问题所在,因为您的<xsl:apply-templates />基本上与<xsl:for-each>相同。

但是:您在两个代码段中使用的选择器有很大差异。您的第一个示例使用了<xsl:for-each select="books/*">,它创建了一个基数为2的节点集,编号,毫不奇怪,1和2.您的第二个代码段使用<xsl:apply-templates />,这是<xsl:apply-templates select="node()">的简写,以及创建基数为五(!)的节点集,其中节点1,3和5是文本节点(恰好只包含空格),节点2和4是您实际想要定位的节点。

解决方案?将您的选择器添加到apply-templates元素,如<xsl:apply-templates select="books/*" />

编辑那么,为什么在第二种情况下设置的节点很大?因为它拾取books的所有子节点,并且XML的工作方式不仅包括元素 - 它还包括文本节点(您确实希望<title><author>拥有一个文本节点子) - 包括来自你的缩进的文本节点,只包含行尾和空格和/或制表符之类的东西,统称为空格。在这些输入变体上尝试原始的第二个代码:

<?xml version="1.0" encoding="UTF-8"?>
<books>
    <book.child.1>
        <title>charithram</title>
        <author>sarika</author>
    </book.child.1>
    <book.child.2>
        <title>doublebell</title>
        <author>psudarsanan</author>
    </book.child.2>
</books>

<?xml version="1.0" encoding="UTF-8"?>
<books><book.child.1>
        <title>charithram</title>
        <author>sarika</author>
    </book.child.1>
    <book.child.2>
        <title>doublebell</title>
        <author>psudarsanan</author>
    </book.child.2>
</books>

<?xml version="1.0" encoding="UTF-8"?>
<books><book.child.1>
        <title>charithram</title>
        <author>sarika</author>
    </book.child.1><book.child.2>
        <title>doublebell</title>
        <author>psudarsanan</author>
    </book.child.2>
</books>

另请注意,元素和文本不是唯一的节点类型:

<?xml version="1.0" encoding="UTF-8"?>
<books>
    <!-- first book -->
    <book.child.1>
        <title>charithram</title>
        <author>sarika</author>
    </book.child.1>
    <!-- second book -->
    <book.child.2>
        <title>doublebell</title>
        <author>psudarsanan</author>
    </book.child.2>
</books>

如果你有匹配这些的模板(例如<xsl:template match='text()'>或更具体的东西),你会在那里找到相应的输出。 XSLT只是默认忽略apply-templates中不匹配的节点。