代码之家  ›  专栏  ›  技术社区  ›  Frerich Raabe

如何优化xpath测试not(previous sibling::sect1)来测试这是否是第一个sect1子元素?

  •  1
  • Frerich Raabe  · 技术社区  · 15 年前

    我正在开发一个XSLT1.0样式表(并使用 xsltproc )我的脚本中的一个模板应该为第一个模板执行一些特殊的处理 <sect1> 给定父节点中的元素,最后一个节点中的元素 <SEC1和GT; 元素。现在,这种特殊处理是这样实现的:

    <xsl:template match="sect1">
      <xsl:if test="not(preceding-sibling::sect1)">
        <!-- Special handling for first sect1 element goes here. -->
      </xsl:if>
      <!-- Common handling for all sect1 elements goes here. -->
      <xsl:if test="not(following-sibling::sect1)">
        <!-- Special handling for last sect1 element goes here. -->
      </xsl:if>
    </xsl:template>
    

    我想知道(出于好奇,脚本的运行时速度对我来说很好):有没有一种更有效的方法可以做到这一点?XSLT处理器是否可能停止组装 preceding-sibling::sect1 在第一次找到匹配后设置节点,因为它知道它只需要找到一个或零个元素?

    3 回复  |  直到 15 年前
        1
  •  1
  •   LarsH    15 年前

    是否可能是XSLT处理器 将停止装配 前一个同级::第1节节点集 在第一次发现匹配后,因为它 知道它只需要找到一个 还是零元素?

    我不知道xsltproc,但是saxon非常擅长这种优化。我相信它只会检查第一次找到的匹配,因为它只需要知道节点集是否为空。

    但是,您可以通过如下更改测试来确保:

      <xsl:if test="not(preceding-sibling::sect1[1])">
    

      <xsl:if test="not(following-sibling::sect1[1])">
    

    因为这只测试沿每个轴的第一个兄弟姐妹。注意,在每种情况下[1]都是指xpath步骤的顺序,即轴的顺序,不一定是文档顺序。所以 preceding-sibling::sect1[1] 指当前元素前面的第一个同级,而不是文档顺序中的第一个同级。因为方向 preceding-sibling 轴是反向的。

        2
  •  1
  •   Jon Hanna    15 年前

    假设调用模板的上下文是子节点选择 然后我提出以下建议。如果他们被调用的上下文是通过一个不同的轴(比如前面的兄弟姐妹或祖先),那么处理它的方法是最好的。

    有两种方法可以简化测试,或者用不同的模板替换它们:

    简单测试:

    <xsl:template match="sect1">
      <xsl:if test="position() = 1">
        <!-- Special handling for first sect1 element goes here. -->
      </xsl:if>
      <!-- Common handling for all sect1 elements goes here. -->
      <xsl:if test="position() = last()">
        <!-- Special handling for last sect1 element goes here. -->
      </xsl:if>
    </xsl:template>
    

    不同的模板:

    <xsl:template name="handleSect1">
      <!-- Common handling for all sect1 elements goes here. -->
    <xsl:template>
    <xsl:template match="sect1">
      <xsl:call-template name="handleSect1"/>
    </xsl:template>
    <xsl:template match="sect1[1]">
      <!-- Special handling for first sect1 element goes here. -->
      <xsl:call-template name="handleSect1"/>
    </xsl:template>
    <xsl:template match="sect1[last()]">
      <xsl:call-template name="handleSect1"/>
      <!-- Special handling for last sect1 element goes here. -->
    </xsl:template>
    <xsl:template match="sect1[position() = 1 and position() = last()]">
      <!-- Special handling for first sect1 element goes here. -->
      <xsl:call-template name="handleSect1"/>
      <!-- Special handling for last sect1 element goes here. -->
    </xsl:template>
    

    既然你说“优化”,我想你会关心哪个过程会更快。它将根据XSLT处理器、处理模式(有些具有“编译”选项,这将影响哪个更有效)和输入XML而变化。最快的可能是这些或你的原创。

    实际上,每一个都应该和另一个一样高效,区别在于处理器所做的优化。

    在这种情况下,我会赞成我的回答中的第一个,因为这是最简洁的,但是如果我不能在所有4个案例之间共享共同的处理方法,我会赞成第二个答案中的方法,然后清楚地标记每个案例的不同方法。

        3
  •  0
  •   AakashM    15 年前

    我觉得你应该能做到

      <xsl:if test="position() = 1">
        <!-- Special handling for first sect1 element goes here. -->
      </xsl:if>
      <!-- Common handling for all sect1 elements goes here. -->
      <xsl:if test="position() = last()">
        <!-- Special handling for last sect1 element goes here. -->
      </xsl:if>
    

    自从 position() last() 上下文敏感。