5

我在确定节点集的正确上下文时遇到了一些麻烦。我有一个看起来有点像这样的模板匹配(使用 XSL 2.0):

<xsl:template match="//chapter/body/*[matches(name(), '^toc')][crossref][not(crossref/@idref='cip' or crossref/@idref='copy')]">
  <xsl:variable name="curr_id" select="crossref/@idref"/>
  <xsl:element name="location">
    <xsl:attribute name="id"><xsl:value-of select="$curr_id"/></xsl:attribute>
    <xsl:attribute name="order"><xsl:value-of select="position()"/></xsl:attribute>
    <xsl:element name="label">
        <text><xsl:value-of select="."/></text>
    </xsl:element>
  </xsl:element>
</xsl:template>

XML 看起来有点像这样:

<chapter id="toc">
  <body>
    <title>Contents</title>
    <tocfm><crossref idref="cip">Catalog</crossref></tocfm>
    <tocfm><crossref idref="copy">Copyright</crossref></tocfm>
    <tocfm><crossref idref="ded">Dedication</crossref></tocfm>
    <toc><crossref idref="prologue">Prologue</crossref></toc>
    <toc><crossref idref="pt1">Book One</crossref></toc>
    <toc><crossref idref="pt2">Book Two</crossref></toc>
    <toc><crossref idref="pt3">Book Three</crossref></toc>
  </body>
</chapter>

我的期望是谓词将生成一个节点集,其中包含:

<tocfm><crossref idref="ded">Dedication</crossref></tocfm>
<toc><crossref idref="prologue">Prologue</crossref></toc>
<toc><crossref idref="pt1">Book One</crossref></toc>
<toc><crossref idref="pt2">Book Two</crossref></toc>
<toc><crossref idref="pt3">Book Three</crossref></toc>

换句话说,所有包含交叉引用的类 toc 元素,其 idref 不是 cip 或副本。模板在输出方面执行此操作,但位置函数似乎不适用于该节点集。相反,它会为奉献生成一个“3”的位置。但是,如果我输出通过使用 [1] 的谓词找到的节点的值,我会得到 Deedication 作为该值。所以,我对正在从事的工作感到困惑。任何人都可以启发我吗?

4

2 回答 2

9

您的期望是错误的,因为它基于对如何定义上下文序列的常见误解。上下文序列不是由模板匹配模式决定的,而是由模板之外的东西决定的。

在某些时候 xsl:apply-templates 会被一个 select 表达式调用。评估此表达式以生成项目序列。当前的上下文序列被推入堆栈。该项目序列成为上下文序列。上下文序列按序列顺序迭代。在每个项目被访问时,该项目成为上下文项目,并且 position() 函数反映了上下文项目在上下文序列中的位置。此时根据匹配表达式和优先级找到合适的模板。匹配表达式不返回序列。它们只是对上下文项的布尔测试 - 上下文项与模板规则匹配或不匹配。如果匹配且优先级最高,则进入模板序列构造函数。此时上下文序列,context item 和 position() 都由客户端 xsl:apply-templates 定义,而不是由匹配条件定义。退出序列构造函数后,控制权返回给客户端 xsl:apply-templates。它将增加 position() 编号,更新上下文项,并再次找到适当的模板。这可能是与前一项相同的模板或不同的模板。

插图

此样式表说明了确定上下文序列和 position() 的是客户端指令(应用模板、for-each 等),而不是模板匹配模式。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>

<xsl:template match="/">
 <t>
   <note message ="apply-templates on EVEN items">
    <xsl:apply-templates select="*/item[ (@id mod 2) = 0]"/>
   </note>  
   <note message ="apply-templates on ODD items">
    <xsl:apply-templates select="*/item[ (@id mod 2) = 1]">
     <xsl:sort select="position()" data-type="number" order="descending"/>
    </xsl:apply-templates>
   </note>  
 </t>
</xsl:template>
      
<xsl:template match="item[@colour='blue']">
 <note message='Brought to you by the Blue template!' positon="{position()}"> 
  <xsl:copy-of select='self::*'/>
  </note>  
</xsl:template>
      
<xsl:template match="item[@colour='red']">
 <note message='Brought to you by the Red template!' positon="{position()}"> 
  <xsl:copy-of select='self::*'/>
  </note>  
</xsl:template>
      
</xsl:stylesheet>
    

...应用于本文件...

<t>
 <item id="1" colour="blue" /> 
 <item id="2" colour="blue" /> 
 <item id="3" colour="blue" /> 
 <item id="4" colour="red" /> 
 <item id="5" colour="red" /> 
 <item id="6" colour="red" /> 
</t>

...产生这个输出...

<t>
  <note message="apply-templates on EVEN items">
    <note message="Brought to you by the Blue template!" positon="1">
      <item id="2" colour="blue" />
    </note>
    <note message="Brought to you by the Red template!" positon="2">
      <item id="4" colour="red" />
    </note>
    <note message="Brought to you by the Red template!" positon="3">
      <item id="6" colour="red" />
    </note>
  </note>
  <note message="apply-templates on ODD items">
    <note message="Brought to you by the Red template!" positon="1">
      <item id="5" colour="red" />
    </note>
    <note message="Brought to you by the Blue template!" positon="2">
      <item id="3" colour="blue" />
    </note>
    <note message="Brought to you by the Blue template!" positon="3">
      <item id="1" colour="blue" />
    </note>
  </note>
</t>
于 2012-07-11T01:37:55.480 回答
3

position()上下文位置。从 XSLT 2.0 规范:

上下文位置是上下文项在当前正在处理的项目序列中的位置。每当上下文项更改时,它都会更改。当使用xsl:apply-templatesor等​​指令xsl:for-each处理一系列项目时,序列中的第一项以上下文位置 1 处理,第二项以上下文位置 2 处理,依此类推。] 返回上下文位置通过 XPath 表达式position()

理解的关键是它xsl:template不会改变上下文项。它可能正在被xsl:apply-templates或改变xsl:for-each。例如,考虑以下代码:

<xsl:apply-templates select="tocfm|toc"/>

当它开始处理Dedication节点时,该节点将成为上下文项,上下文位置成为该节点在输入序列中的位置(所有tocfmtoc元素的并集)。这或类似的东西可能是你的 3 的来源。

正如apply-templates规范的一部分所说:

xsl:apply-templates指令将一系列节点(通常是源树中的节点)作为输入 […] 如果指令有一个或多个子节点xsl:sort,则输入序列按照 13 排序中的描述进行排序。这种排序的结果在下面称为排序序列;如果没有xsl:sort元素,则排序后的序列与输入序列相同。[…] 输入序列中的每个节点都通过查找与该节点的模式匹配的模板规则来处理。[…] 匹配排序序列中第 N 个节点的规则以该节点作为上下文项,N 作为上下文位置,排序序列的长度作为上下文大小进行评估。

您可能会发现此FAQ 条目很有用(尽管它根据 XSLT 1.0 的position()当前节点列表概念解释了该问题,而 XSLT 2.0 中未使用该概念)。

于 2012-07-11T01:38:10.233 回答