1

我有这个 XSLT 2.0 模板:

<xsl:template match="footnote">
    <xsl:variable name = "string" select="./text()"/>
    <xsl:variable name = "bool">
        <xsl:choose>
            <xsl:when test="$string = preceding::footnote/text()">
                <xsl:text>false</xsl:text>
            </xsl:when>
            <xsl:otherwise>
                <xsl:text>true</xsl:text>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:variable>
    <xsl:if test="$bool = 'true'">
        <xsl:variable name="footnoteCount">
            <xsl:call-template name="getItemNumber">
                <xsl:with-param name="node" select="."/>
            </xsl:call-template>
        </xsl:variable>
    <!-- DO XSL-FO TRANSFORMATION STUFF-->
    </xsl:if> 
    <xsl:if test="$bool = 'false'">
        <xsl:variable name = "footnoteCount">
            <xsl:if test="$string = preceding::footnote/text()">
                <xsl:value-of select="preceding::footnote/$footnoteCount"/>
            </xsl:if>
        </xsl:variable>
        <!--DO XSL-FO TRANSFORMATION STUFF-->
    </xsl:if>
</xsl:template>

编辑了示例 XML。我想改变这个:

<footnote>Foo bar</footnote>
<footnote>Bar foo</footnote>
<footnote>Foo bar</footnote>
<footnote>Foo bar</footnote>
<footnote>Bar</footnote>
<footnote>Foo</footnote>

进入这个:

<footnote>Foo bar</footnote>
<footnote>Bar foo</footnote>
<footnote>Bar</footnote>
<footnote>Foo</footnote

然后使用 XSL-FO 对其进行样式化。这种样式的目的是主体中的文本将有一个编号的引用,由 表示$footnotecount,然后在页面底部呈现的脚注。我需要转换文档,以便重复的脚注只呈现一次,并且$footnoteCount每个重复的数字参考 ( ) 都是相同的。

所以我试图用这个模板做的是:

  1. 确定具有当前节点文本的脚注元素是否已存在。
  2. 如果它不存在(即,'$bool' 为 'true'),找到前一个脚注的编号,增加它(这在 'getItemNumber' 模板中完成)并创建一个“新”脚注。如果确实存在($bool 为 'false'),则获取文本匹配的节点的 $footnoteCount 变量并将其用于当前节点。

这是我遇到麻烦的脚注已经存在的场景。我不知道如何从先前的特定节点获取 $footnoteCount 变量,具体取决于节点是否满足特定条件(其文本是否与当前节点中的 $string 变量相同)。由于 $footnoteCount 变量仅有条件地存在(即使在实践中它始终存在,因为 $bool 必须为真或假),这一事实变得更加困难。

有人对在这里做什么有建议吗?

4

2 回答 2

1

这看起来像一个分组问题,在 XSLT2.0 中,您可以使用xsl:for-each-group元素来获取不同的元素

<xsl:for-each-group select="footnote" group-by=".">

我认为您需要一种不同的方法来进行编号。首先,您可以创建一个变量来保存脚注描述及其索引的“查找”

    <xsl:variable name="footnotes">
        <xsl:for-each-group select="//footnote" group-by=".">
            <footnote id="{position()}">
                <xsl:value-of select="."/>
            </footnote>
        </xsl:for-each-group>
    </xsl:variable>

这意味着脚注变量包含以下元素

<footnote id="1">Foo bar</footnote>
<footnote id="2">Bar foo</footnote>
<footnote id="3">Bar</footnote>
<footnote id="4">Foo</footnote>

然后,要用数字引用替换现有的脚注元素,您将拥有这样的模板

    <xsl:template match="footnote">
        <footnote>
            <xsl:value-of select="$footnotes/footnote[. = current()]/@id"/>
        </footnote>
    </xsl:template>  

尝试以下 XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:variable name="footnotes">
        <xsl:for-each-group select="//footnote" group-by=".">
            <footnote id="{position()}">
                <xsl:value-of select="."/>
            </footnote>
        </xsl:for-each-group>
    </xsl:variable>

    <xsl:template match="/*">
        <xsl:apply-templates select="footnote"/>

        Footnotes
        <xsl:copy-of select="$footnotes"/>
    </xsl:template>

    <xsl:template match="footnote">
        <footnote>
            <xsl:value-of select="$footnotes/footnote[. = current()]/@id"/>
        </footnote>
    </xsl:template>
</xsl:stylesheet>

当应用于您的示例 XML(假设是根元素)时,输出以下内容

<footnote>1</footnote>
<footnote>2</footnote>
<footnote>1</footnote>
<footnote>1</footnote>
<footnote>3</footnote>
<footnote>4</footnote>

Footnotes
<footnote id="1">Foo bar</footnote>
<footnote id="2">Bar foo</footnote>
<footnote id="3">Bar</footnote>
<footnote id="4">Foo</footnote>
于 2012-12-11T08:54:18.393 回答
1

除了未能使用 xsl:for-each-group 之外,您的代码还有许多其他问题。例如,采取这个:

<xsl:variable name = "bool">
    <xsl:choose>
        <xsl:when test="$string = preceding::footnote/text()">
            <xsl:text>false</xsl:text>
        </xsl:when>
        <xsl:otherwise>
            <xsl:text>true</xsl:text>
        </xsl:otherwise>
    </xsl:choose>
</xsl:variable>

你可以写成

<xsl:variable name="bool" as="xs:boolean()" 
    select="$string = preceding::footnote"/>

然后你这样做:

<xsl:if test="$bool = 'true'">
    <xsl:variable name="footnoteCount">
        <xsl:call-template name="getItemNumber">
            <xsl:with-param name="node" select="."/>
        </xsl:call-template>
    </xsl:variable>
</xsl:if>

这是完全没用的:变量一被声明就超出范围,所以它永远不能被引用。

您需要阅读一些有关 XSLT 的背景知识,还有很多想法您还没有掌握。

于 2012-12-11T10:40:08.217 回答