在xslt中递增值

时间:2012-08-01 09:48:23

标签: xml xslt xpath

抱歉再次提出这个问题。当我使用上一个问题的答案时,我遇到了一些问题。假设我的xml像这样,

<comp>
<section id="1">
 <p>text</p>
 <figure xml:id="c1-fig-002"/>
 <p>text</p>
 <figure xml:id="c1-fig-003"/>
</section>
<section id="2">
 <p>text</p>
 <figure xml:id="c1-fig-003"/>
 <figure xml:id="c1-fig-004" resumeNumberingAt="7"/>
 <figure xml:id="c1-fig-005"/>
 <p>text</p>
</section>
<section id="3">
 <p>text</p>
 <figure xml:id="c1-fig-006"/>
 <figure xml:id="c1-fig-007" resumeNumberingAt="18"/>
 <p>text</p>
 <figure xml:id="c1-fig-008"/>
 <p>text</p>
 <figure xml:id="c1-fig-009"/>
</section>
</comp>

我正在使用xslt获得以下结果,

<comp>
<section id="1">
 <p>text</p>
 <figure xml:id="c1-fig-002"/>
 <fignum>2</fignum>
 <p>text</p>
 <figure xml:id="c1-fig-003"/>
 <fignum>3</fignum>
</section>
<section id="2">
 <p>text</p>
 <figure xml:id="c1-fig-003"/>
 <fignum>3</fignum>
 <figure xml:id="c1-fig-004" resumeNumberingAt="7"/>
 <fignum>7</fignum>
 <figure xml:id="c1-fig-005"/>
 <fignum>8</fignum>
 <p>text</p>
</section>
<section id="3">
 <p>text</p>
 <figure xml:id="c1-fig-006"/>
 <fignum>9</fignum>
 <figure xml:id="c1-fig-007" resumeNumberingAt="18"/>
 <fignum>18</fignum>
 <p>text</p>
 <figure xml:id="c1-fig-008"/>
 <fignum>19</fignum>
 <p>text</p>
 <figure xml:id="c1-fig-009"/>
 <fignum>20</fignum>
</section>
</comp>

我需要从2的{​​{1}}之后的数字中获取值。

如果有一个属性resumeNumberingAt,那么我需要使用该值而不是正常值,并增加以下节点的值。我使用以下xslt来做到这一点,但它不起作用。

c1-fig-002

1 个答案:

答案 0 :(得分:1)

此XSLT 1.0样式表......

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

<xsl:template match="@*|node()">
 <xsl:copy>
  <xsl:apply-templates select="@*|node()"/>
 </xsl:copy>
</xsl:template>

<xsl:template match="figure">
 <xsl:copy>
  <xsl:apply-templates select="@*|node()"/>
 </xsl:copy>
 <fignum>
   <xsl:variable name="base-node" select="
     ((preceding::figure[@resumeNumberingAt] |
       self     ::figure[@resumeNumberingAt] )[last()]  |
       self     ::figure)[1]" />
   <xsl:variable name="base">
     <xsl:apply-templates select="$base-node" mode="numbering" />
   </xsl:variable>
   <xsl:variable name="prev-figs"      select="preceding::figure" />
   <xsl:variable name="prev-fig-count" select="count($prev-figs)" />
   <xsl:value-of select="$base +
     count(($base-node/following::figure|$base-node)
       [count(. | $prev-figs) = $prev-fig-count])" />
 </fignum> 
</xsl:template>

<xsl:template match="figure[@resumeNumberingAt]" mode="numbering">
 <xsl:value-of select="@resumeNumberingAt" /> 
</xsl:template>

<xsl:template match="figure" mode="numbering">
 <xsl:value-of select="substring(@xml:id, 8, 3)" /> 
</xsl:template>

</xsl:stylesheet>

...获取您的样本输入文档并生成所述的预期输出文档。此解决方案已在Microsoft XslCompiledTransform XSLT引擎

上成功测试

说明

在无模式图模板中,我们将复制输入图元素并创建以下fignum元素。变量$ base-node将是我们基于该图号的基本节点。看一下细节,这个表达......

(preceding::figure[@resumeNumberingAt] |
 self     ::figure[@resumeNumberingAt] )[last()]

...将引用具有@resumeNumberingAt属性的最近的前一个数字元素,或者如果此属性具有@resumeNumberingAt属性,则引用此对象(焦点节点)。一般来说,这将是我们计算fignum的基础。但是,当焦点节点在第一个@resumeNumberingAt之前时,一个例外。在这种情况下,我们将基于上下文节点的计数(通过xml:id属性)。因此,在所有情况下,我们都可以找到基节点,没有任何带有此表达式的笨拙的xsl:if语句......

 ((preceding::figure[@resumeNumberingAt] |
   self     ::figure[@resumeNumberingAt] )[last()]  |
   self     ::figure)[1]

现在计算基数。我们有基节点。如果它具有@resumeNumberingAt属性,那么这是基数,否则它基于@xml:id属性。而不是做一个明确的测试,我们可以简单地利用模板选择机制和模式来计算基数。例如,对于节点...

<figure xml:id="c1-fig-006"/>

......基本节点是......

<figure xml:id="c1-fig-004" resumeNumberingAt="7"/>

...因此基数为7.稍后需要将此偏移+2以获得所需的fignum 9.相反,对于节点......

<figure xml:id="c1-fig-003"/>

...基本节点本身,基值为3('003'转换为整数)。稍后将需要将此偏移+0以获得所需的fignum 3。

变量$ prev-figs是此前一个数字元素的集合。所以现在我们通过将基本fignum偏移基本节点和焦点节点(包括基节点,但不包括焦点节点)之间的数字计算来计算fignum。这个偏移是两组之间的交集:

(1)以下(包括)基节点的数字;和

(2)焦点节点之前的数字。

在XSLT 1.0中,计算两组交集的一般方法是......

$node-set1[count(. | $node-set2) = count($node-set2)]

......而这正是我们对这条指令的所作所为......

<xsl:value-of select="$base +
 count(($base-node/following::figure|$base-node)
   [count(. | $prev-figs) = $prev-fig-count])" />

一般原则

采用以下一般原则:

  1. 使用union运算符(|)和位置谓词来避免显式分支指令。
  2. 使用模板匹配机制来避免显式分支指令,提供强大的功能,可扩展性和简单性。
  3. 根据需要使用XSLT 1.0 set intersection的模式。