计算之前的节点 returns 个意外结果

Counting previous nodes returns unexpected results

我想使用逐项列表而不是硬中断,请参见示例:

<para>line1<?linebreak?>
line2<?linebreak?>
line3</para>

但是,我在递归模板中遇到了奇怪的行为,导致无法正确处理第二行。我已经创建了简化的测试用例——不再是递归的。如果以这种方式使用 count(preceding::processing-instruction('linebreak')) = 0 表达式,则不会返回任何内容,但我希望返回第二行。

<line>line1</line><node>
line2<?linebreak?>
line3</node>
line2

<node> 元素在这里用于调试目的。它确认我处理了预期的数据。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:template match="para[processing-instruction('linebreak')]">
        <xsl:call-template name="getLine">
            <xsl:with-param name="node" select="./node()"/>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="getLine">
        <xsl:param name="node"/>

        <line>
            <xsl:copy-of
                select="$node/self::processing-instruction('linebreak')[not(preceding::processing-instruction('linebreak'))]/preceding::node()"
            />
        </line>

        <xsl:call-template name="getSecondLine">
            <xsl:with-param name="node"
                select="$node/self::processing-instruction('linebreak')[not(preceding::processing-instruction('linebreak'))]/following::node()"
            />
        </xsl:call-template>

    </xsl:template>

    <xsl:template name="getSecondLine">
        <xsl:param name="node"/>

        <node>
            <xsl:copy-of select="$node"/>
        </node>

        <xsl:copy-of
            select="$node/self::processing-instruction('linebreak')[count(preceding::processing-instruction('linebreak')) = 0]/preceding::node()"
        />
    </xsl:template>

</xsl:stylesheet>

在 Saxon HE/EE 9.6.0.7 中测试(在 Oxygen XML Editor 18 中)。

第一个换行符的处理工作正常:

<line>
   <xsl:copy-of
     select="$node/self::processing-instruction('linebreak')
              [not(preceding::processing-instruction('linebreak'))]
              /preceding::node()"/>
</line>

尽管仅针对此示例;在更复杂的数据上,您会得到错误的结果,因为您应该使用 preceding-sibling 轴而不是 preceding 轴。

但是代码可以大大简化,我会把 select 表达式写成:

select="$node[self::processing-instruction('linebreak')][1]
        /preceding-sibling::node()"

第二个换行符的处理看起来很混乱。您正在传递参数

$node/self::processing-instruction('linebreak')
   [not(preceding::processing-instruction('linebreak'))]
   /following::node()"

有效

select="$node[self::processing-instruction('linebreak')][1]
            /following-sibling::node()"

选择三个节点

line2<?linebreak?>line3

(加上空格),您在 <node> 元素中输出,生成

<node>line2<?linebreak?>line3</node>

(再次忽略空格)

然后你做

select="$node/self::processing-instruction('linebreak')
  [count(preceding::processing-instruction('linebreak'))=0]
  /preceding::node()"

这里$node/self::processing-instruction('linebreak')选择这三个节点中的第二个,也就是第二条换行处理指令。前面(或前面的兄弟)处理指令的计数是 1,因为你正在处理的是第二个。

我不太确定您在想什么,但我怀疑您的错误是将 "preceding" 和 "following" 视为相对于节点在 [= 中的位置进行选择22=] 序列,而不是相对于原始源代码树中的其他节点。我建议阅读 XPath 参考书中描述各种轴的部分。