【问题标题】:Get conditional value from previous node从前一个节点获取条件值
【发布时间】:2012-12-11 08:02:17
【问题描述】:

我有这个 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 必须为真或假),这一事实变得更加困难。

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

【问题讨论】:

  • 能否请您也发布getItemNumber 模板。一旦我知道你打算做什么,我可以优化代码!
  • 我不认为 getItemNumber 模板与问题相关 - 它只是生成一个数字,如果当前节点文本的脚注不存在,则使用该数字。当包含当前节点文本的脚注确实存在时,我更关心会发生什么。另外,getItemNumber 模板调用了其他三个模板,如果我将它们全部发布,那么这个问题会变得非常复杂。 :)
  • 您使用的是 XSLT1.0 还是 XSLT2.0?
  • 另外,澄清一下......如果你有Footnote 1, Footnote 2, Footnote 4,输出会是Footnote 1, Footnote 2, Footnote 3吗?
  • 不,Footnote 1, Footnote 2 只是占位符数据——实际上它只是任何字符串。这个想法是摆脱“重复”脚注,而不是按照文本中出现的数字对它们进行排序。

标签: xslt xslt-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>

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

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

然后,要将现有的 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>

【讨论】:

  • 感谢您深思熟虑的答案,但这似乎并不能解决我需要在匹配的脚节点节点中获取 $footnoteCount 变量的值的问题。如果这只是摆脱重复的问题,那么我的代码已经做到了(尽管不像你的那么整洁,当然)。
  • 也许您可以修改您的示例 XML 以包含更具代表性的数据(即输入示例不包含任何编号,如果是这种情况)?谢谢!
  • 我已经更改了 XML,并在下面添加了一个段落,准确地解释了我需要对这个样式表做什么。
  • 这是一个巨大的帮助。非常感谢。
【解决方案2】:

除了未能使用 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 的背景知识,有很多想法您还没有掌握。

【讨论】:

  • 首先,感谢有关布尔值的提示。其次,它不会在声明后立即超出范围 - 正如我在我提出问题的评论中所说,我在同一个 if 块中“执行 XSL-FO TRANSFORMATION STUFF”。 XSL-FO 转换的东西经常使用 footnoteCount 变量。有很多关于 XSLT 的想法我还没有掌握——这就是我在这里询问它的原因。阅读能帮助你的只有这么多。这不是一个很有建设性的答案。
猜你喜欢
  • 1970-01-01
  • 2011-09-07
  • 1970-01-01
  • 2018-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多