Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Optimization 如何优化XPath测试not(前面的同级::sect1)以测试这是否是第一个sect1子元素?_Optimization_Xslt_Xpath - Fatal编程技术网

Optimization 如何优化XPath测试not(前面的同级::sect1)以测试这是否是第一个sect1子元素?

Optimization 如何优化XPath测试not(前面的同级::sect1)以测试这是否是第一个sect1子元素?,optimization,xslt,xpath,Optimization,Xslt,Xpath,我正在开发XSLT1.0样式表(并使用它进行应用)。脚本中的一个模板应该对给定父节点中的第一个元素执行一些特殊处理,对最后一个元素执行一些特殊处理。现在,这种特殊处理是这样实现的: <xsl:template match="sect1"> <xsl:if test="not(preceding-sibling::sect1)"> <!-- Special handling for first sect1 element goes here. -->

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

<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处理器是否可能在第一次找到匹配项后停止组装
前面的同级::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>


由于
position()
last()
是上下文敏感的。

假设调用模板的上下文是子节点选择,那么我提供以下内容。如果他们被调用的上下文是通过不同的轴(比如前面的兄弟姐妹或祖先),那么接近它的方式是最好的

两种可能性是简化测试,或者用不同的模板替换它们:

<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>
更简单的测试:

<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个案例之间共享共同的处理方式,我会倾向于第二个答案中的方法,然后清楚地标记出每个案例的不同方法

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

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

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

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



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

这不是有二次复杂性吗,因为position()是(可能?)一个
O(n)
函数吗?我刚刚意识到:这是不等价的:position()在所有子级中返回position()。我只是想知道它是否是第一个
sect1
元素,而不是第一个子元素。这取决于它的使用方式。我认为在匹配模式中或在for each循环中,yes position()和last()与上下文列表相关。但是,在其他地方,例如XPath表达式中“/”之后,上下文是不同的。第一个建议真的正确吗?position()是否仅当
sect1
元素是第一个子元素时才返回1?我希望为第一个
sect1
元素执行代码,即使它不是第一个子元素。它返回给定上下文中的位置。如果上下文是其他节点可以继续进行的,那么测试可以是“./sect1[1]=current()”。我认为您真的不需要分离的命名模板,您可以将@name添加到匹配“sect1”的规则中。也适用于第一个和最后一个匹配的规则,以避免规则中重复的代码只匹配一次(因此,第一个和最后一个)。关于您最后的评论:要测试标识,您应该使用
generate id(../sect1[1])=generate id(current())
。最后,第一个建议不仅适用于子轴模板应用,而且还需要元素测试,如
apply templates select=“sect1”
Yes中所述,特定的XSLT处理器优化可以将此作为一种快捷方式,但从
谓词过滤节点集以生成一个新的节点集,从
以下同级轴包含上下文节点的所有同级
,不清楚这是否是您可以信任的优化。在这种情况下,以及在其他情况下,模式匹配是最好的方法。@Alejandro:我同意,在不知道正在使用什么处理器的情况下,不能保证这种优化会发生。然而OP询问优化的可能性,我相信Saxon的可能性很高。从规范中引用的部分指定了语义,而不是实现。即使“以下同级轴包含上下文节点的所有以下同级”,这也并不意味着处理器必须实例化或处理所有同级轴才能兼容。