【问题标题】:How to use an incremented counter to provide a unique id in XSLT?如何使用递增计数器在 XSLT 中提供唯一 ID?
【发布时间】:2009-11-10 18:34:09
【问题描述】:

我正在使用 XSLT 将一个非常大的 XML 文档转换为 (X)HTML。对于某些标签,我将它们转换为<div>。我希望能够为这些标签创建一个唯一 ID,使用递增的整数来形成唯一 ID 的一部分。

我使用的规则的一个例子是:

<xsl:template match="bookcoll/book">
    <div class="book">
        <xsl:apply-templates/>
    </div>
</xsl:template>

这个 XSLT 模板运行良好。我现在想要的是标签:

<div class="book">;  

成为:

<div class="book" id="book-[COUNTER-VALUE]">  

理想情况下,计数器从 1 开始,而不是 0。

我不知道这是否有很大不同,我正在使用 Java 包 javax.xml.parsers 和 javax.xml.transform 来执行实际的转换。我有点 XSLT 菜鸟,所以如果我遗漏了任何相关信息,请告诉我。

如何在 XSLT 中实现这一点?

【问题讨论】:

  • 代码缩进 4 个空格,如下所示:stackoverflow.com/editing-help
  • 啊,好多了。我试图用 pre 和 code 标签来做这件事,奇怪的事情正在发生。谢谢!
  • @Grundlefleck:您的 XSLT 的(大量)修改和注释版本可在 pastebin.com/m63e66eea 获得。我希望我设法做对了,如果没有,更改应该很容易进行。玩得开心。 :-)
  • 哦,另一个版本 2 在这里:pastebin.com/f77f6a871。替代方案(可能)更好,因为如果您忘记为某个标签编写模板(显式优于隐式),它不会导致输出中出现不需要的元素。
  • 里面有一些有趣的和新的(对我来说)东西供我学习。非常感谢,托马拉克! :-)

标签: java xslt xhtml


【解决方案1】:

自然/惯用/故障安全解决方案是:

<div class="book" id="book-{generate-id()}">

它不是递增的,但保证是唯一的。它会生成 HTML 有效的 ID 字符串 (name tokens)。

编辑:如果它必须递增,请执行以下操作:

<!-- in the calling template… -->
<xsl:apply-templates select="bookcoll/book[xpath to filter them if necessary]" />

<!-- …later -->
<xsl:template match="bookcoll/book">
  <div class="book" id="book-{position()}">
    <xsl:apply-templates/>
  </div>
</xsl:template>

您可以使用format-number() 来调整position() 的输出以满足您的需求。

position() 将返回相对于当前正在处理的“批次”的节点位置。通过显式调用&lt;xsl:apply-templates&gt;,您可以确保它们按照您想要的方式编号。

【讨论】:

  • 我已经读过这种方法,但增量确实是我所追求的:-(
  • ${COUNTER} 是我展示它是一个变量的方式(就像 bash 的做法一样)。编辑问题以消除歧义。
  • {} 已经在 XSLT 中进行了变量插值,$ 仅表示一个变量。
  • 这可能超出了问题的范围。 position() 递增 2,即它变为 book-2、book-4... 我假设我的模板匹配的节点比我预期的 match="bookcoll/book" 多。您如何建议我找出该匹配找到的节点?
  • 例如,您可能正在处理&lt;book&gt; 节点之间的空文本节点。这就是为什么我说“明确调用&lt;xsl:apply-templates&gt;”。一个赤裸裸的&lt;xsl:apply-templates /&gt; 处理它可以找到的任何子节点,包括文本节点。
【解决方案2】:

正如之前多次建议的那样,您需要position(),但您必须使用xsl:for-each 遍历项目:

<xsl:template match="bookcoll">
    <xsl:for-each select="book">
        <div class="book" id="book-{position()}">
            <xsl:apply-templates/>
        </div>
    </xsl:for-each>
</xsl:template>

这将产生类似:

<div class="book" id="book-1">book1</div>
<div class="book" id="book-2">book2</div>
<div class="book" id="book-3">book3</div>

<bookcoll>
    <book>book1</book>
    <book>book2</book>
    <book>book3</book>
</bookcoll>

【讨论】:

  • 我已经在处理 &lt;xsl:template match="bookcoll"&gt; 以将软管转换为 div。我似乎无法让现有位与 for-each 循环配合得很好。能做到吗?
  • 您的 XML 是否与我发布的 XML 示例基本匹配?如果是这样,发布的 XSL 示例应该可以。
  • 确实如此,但我也想将&lt;bookcoll&gt; 转换为&lt;div&gt;,并且在这两个方面都遇到了一些麻烦。得到它的工作,但谢谢。 +1 顺便说一句
【解决方案3】:

您可以将标注添加到 Java 类上的静态方法到您的转换中...它可以工作,但也有一些缺点,例如 1)现在您的转换与一些 Java 代码相关联,并且更难在 Oxygen 等外部工具中测试/调试(尽管有一些方法可以缓解这种情况) 2)您必须将状态保持为静态或线程本地,这可能会引入各种问题(同步问题,如果您多次执行此操作,则有关重置的问题等)

【讨论】:

  • 转换不会是常规事件。它们已经开始使用 Java 代码,并且它们不需要高性能。您是否有此技术的教程的来源或链接?
【解决方案4】:

查看 position() 函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多