0

很抱歉再次问这个问题。当我使用上一个问题的答案时,我遇到了一些问题。假设我的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>

我需要从 fig 之后的数字中获取2价值c1-fig-002

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

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

  <xsl:template match="figure[@resumeNumberingAt != '']">
    <xsl:call-template name="fig">
      <xsl:with-param name="sequence" select="@resumeNumberingAt"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template match ="section">
   <!--some operation-->
  </xsl:template>
  <xsl:template match ="p">
  <!--some operation-->
  </xsl:template>
  <xsl:template match="figure" name="fig">
    <xsl:param name="sequence" select="substring(@xml:id, 10, 1)"/>
    <figure>
      <xsl:apply-templates select="@*"/>
      <fignum>
        <xsl:value-of select="$sequence"/>
      </fignum>
    </figure>
    <xsl:apply-templates select="following-sibling::figure[1]">
      <xsl:with-param name="sequence" select="$sequence + 1"/>
    </xsl:apply-templates>
  </xsl:template>

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

1 回答 1

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. 使用联合运算符 (|) 和位置谓词来避免显式分支指令。
  2. 使用模板匹配机制来避免显式分支指令,从而提供强大、可扩展性和简单性。
  3. 根据需要使用 XSLT 1.0 设置交集的模式。
于 2012-08-01T13:34:23.523 回答