从前一节点获取条件值

时间:2012-12-11 08:02:17

标签: xslt xslt-2.0

我有这个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'模板中完成的)并创建一个'new'脚注。如果确实存在($ bool为'false'),请获取文本匹配的节点的$ footnoteCount变量,并将其用于当前节点。
  3. 这就是脚本已经存在的情况,我遇到了麻烦。我不知道如何从以前的特定节点获取$ footnoteCount变量,这取决于节点是否满足某个条件(其文本是否与当前节点中的$ string变量相同)。由于$ footnoteCount变量只是有条件地存在(即使在实践中它总是存在,因为$ bool必须是true或false),这变得更加困难。

    有没有人建议在这做什么?

2 个答案:

答案 0 :(得分: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>

答案 1 :(得分: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的背景阅读,还有很多你还没有掌握的想法。