XSLT:查找给定节点的数量

时间:2011-09-08 16:42:36

标签: xslt

我有一个表示逻辑推导的XML结构,它看起来像这样:

<derivation>
  <step name="foo">
    <derive>[...]</derive>
    <by>[...]</by>
  </step>
  <step name="bar">
    <derive>[...]</derive>
    <by>
      <from name="foo"/>, conjunction elimination
    </by>
  </step>
  <step name="baz">
    <derive>[...]</derive>
    <by>
      <from name="bar"/>, existential quantification
    </by>
  </step>
  [...]
</derivation>

派生中的每个<step>都有一个数字 - 例如,name="foo"的数字为1,而name="bar"的数字为2 },name="baz"的数字为3,依此类推。在<step>内,我可以找到<xsl:number/>的数字。好到目前为止。

现在,发生了元素<from name="bar"/>,我希望将其替换为<step>元素name="bar" 的数字。这里有三个子问题需要解决:

  • 找到<from>的{​​{1}}元素的最新祖先。
  • 从那里,找到第一个<derivation>元素与<step>的孩子。在上面的例子中,这将找到name="bar"的第二个孩子。
  • 确定该元素的编号。在上面,那将是<derivation>

有人可以将这些子问题的解决方案联系起来以满足我的要求吗?

4 个答案:

答案 0 :(得分:2)

此转化

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

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

 <xsl:template match="from[@name]">
  <xsl:variable name="vReferred" select=
    "ancestor::derivation[1]/step[@name = current()/@name]"/>

   <xsl:for-each select="$vReferred">
     <xsl:number count="step" level="any"/>
   </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<derivation>
    <step name="foo">
        <derive>[...]</derive>
        <by>[...]</by>
    </step>
    <step name="bar">
        <derive>[...]</derive>
        <by>
            <from name="foo"/>, conjunction elimination     
        </by>
    </step>
    <step name="baz">
        <derive>[...]</derive>
        <by>
            <from name="bar"/>, existential quantification     
        </by>
    </step>   [...] 
</derivation>

生成想要的正确结果

<derivation>
   <step name="foo">
      <derive>[...]</derive>
      <by>[...]</by>
   </step>
   <step name="bar">
      <derive>[...]</derive>
      <by>1, conjunction elimination     
        </by>
   </step>
   <step name="baz">
      <derive>[...]</derive>
      <by>2, existential quantification     
        </by>
   </step>   [...] 
</derivation>

答案 1 :(得分:1)

XPath轴的乐趣......

count(ancestor::derivation/step[@name=$name]/preceding-sibling::step)+1

这会抓取最近的祖先,它是一个派生,用正确的名称获取它的子步骤,然后获取所有名为step的兄弟姐妹。它计算它们并加1(因为第2步将有1个前面的兄弟)。

XPath axis reference

答案 2 :(得分:1)

使用密钥的另一种解决方案(如果平均有多个对同一步骤的引用可能会更有效):

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

 <xsl:key name="kStepByName" match="derivation/step"
         use="@name"/>

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

 <xsl:template match="from[@name]">
  <xsl:variable name="vReferred" select=
    "key('kStepByName',@name)"/>

   <xsl:for-each select="$vReferred">
     <xsl:number count="step" level="any"/>
   </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

答案 3 :(得分:0)

虽然已发布的两个解决方案都可以,但仅供参考,我正在添加另一种可能的解决方案。

类似的东西:

<xsl:template match="from">
  <xsl:variable name="ref" select="@name"/>
  <xsl:apply-templates mode="number" select="ancestor::derivation/step">
    <xsl:with-param name="ref" select="$ref"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template name="step" mode="number">
  <xsl:param name="ref"/>
  <xsl:if test="@name=$ref">
    Item no. <xsl:value-of select="position()"/>
  </xsl:if>
</xsl:template>

请注意,我已经有好几年没有编写XSLT了,而这个解决方案背后的想法应该是正确的,语法可能完全错误。