用于在 HTML 中生成列表的 XSLT 通用模板

Posted

技术标签:

【中文标题】用于在 HTML 中生成列表的 XSLT 通用模板【英文标题】:XSLT generic template to generate lists in HTML 【发布时间】:2021-09-25 22:36:52 【问题描述】:

我想编写一些通用模板来将节点集合转换为 html 列表。集合的每个元素都应该对应一个列表项。理想情况下我会写

<xsl:apply-templates select="..." mode="ul"/>

连同与选择中的各个元素匹配的模板,生成的 HTML 应该看起来像

<ul>
  <li>Transformation of first element in selection</li>
  <li>Transformation of second element</li>
  ...
</ul>

即每个&lt;li&gt;的内容都是由非泛型模板生成的;但是列表结构本身是由通用结构生成的。问题是编写一个通用模板,为任何非空集合生成此列表结构,并且为空集合不输出。

我尝试了以下方法:

<xsl:template match="*" mode="ul">
  <xsl:if test="count(*) > 0">
    <ul>
      <xsl:apply-templates select="*" mode="li"/>
    </ul>
  </xsl:if>
</xsl:template>

<xsl:template match="*" mode="li">
  <li>
    <xsl:apply-templates select="." />
  </li>
</xsl:template>

但这不起作用:集合的每个元素将单独变为&lt;ul&gt;。从概念上讲,我想要的是将集合本身转换为&lt;ul&gt;,然后将集合的元素转换为单独的&lt;li&gt;s。 p>

这里很重要:

    非空集合的测试应该在通用模板中,因为我不想用条件包装对这个模板的每次调用,也不想输出空的@9​​87654328@元素集合为空。

    在我正在转换的 XML 文档中,集合中的元素通常没有共同的父级。这意味着我不能将父级转换为&lt;ul&gt;,将其子级转换为&lt;li&gt;s;源文档中没有与&lt;ul&gt; 对应的元素。

这可能吗?我所做的搜索越来越多地向我表明它不是,但这对我来说似乎很疯狂,因为这一定是一个非常常见的用例。

【问题讨论】:

一个模板匹配单个项目或节点,不清楚你用“集合”指的是什么。 “集合”是指与 XPath 表达式匹配的节点集,例如 apply-templates 的 select="..." 属性。 “选择”是一个更好的词吗?还是“节点集”? 在 XSLT 1 中,它是一个节点集,在以后的版本中,一般是一系列节点或项。 【参考方案1】:

至少在理论上,你应该可以做这样的事情:

    <xsl:call-template name="ul">
        <xsl:with-param name="nodes" select="..."/>
    </xsl:call-template>

然后:

<xsl:template name="ul">
    <xsl:param name="nodes"/>
    <xsl:if test="$nodes">
        <ul>
            <xsl:apply-templates select="$nodes" mode="li"/>
        </ul>
    </xsl:if>
</xsl:template>

<xsl:template match="*" mode="li">
    <li>
        <xsl:apply-templates select="." />
    </li>
</xsl:template>

这将在将 li 模板应用于 selection 中的每个元素(我认为,你称之为 collection )。


这是值得的努力吗?可能不是。 XML 输入有各种各样的模式,通用样式表很少能适应所有模式。编写处理已知模式的特定样式表要容易得多。

【讨论】:

谢谢。我同意如果必须使用这样的参数可能不值得付出努力——除非调用可以是单行的,否则它并没有真正节省任何代码行,只是增加了一层间接性。但是,在没有办法抽象出来的情况下到处写这个模式让我很困扰! 嗯,它确实实现了创建一个“函数”的目的,您可以从任何地方调用并修改一次以应用于所有人。 XSLT 自然是冗长的(尤其是 XSLT 1.0),因此“节省代码行数”通常是不可行的。但在 XSLT 2.0 或更高版本中,您可以使其成为真正的函数并通过单行方式调用它:xsltfiddle.liberty-development.net/3MP42Nh 感谢您的提琴;在 XSLT 2.0 中,这似乎是一种不错的方式。【参考方案2】:

在 XSLT 3.0(使用 XPath 3.1)中,您可以这样做

<xsl:apply-templates select="array..." mode="ul"/>

<xsl:template match="." mode="ul">
    <ul>
      <xsl:apply-templates select="?*" mode="li"/>
    </ul>
</xsl:template>

<xsl:template match="*" mode="li">
  <li>
    <xsl:apply-templates select="." />
  </li>
</xsl:template>

通过将您的“集合”包装到一个数组中,您可以使其成为一个单独的项目,通过一次调用模板规则进行匹配,该模板规则可以输出所需的&lt;ul&gt; 元素。

【讨论】:

那么,将ul 包装成xsl:where-populated 来实现xsl:if test="count(*) &gt; 0" 的初始尝试是有意义的。 谢谢。这似乎是我正在寻找的。但是,在 XSLT 3.0 之前没有可比的东西吗? 不,对于早期版本,调用模板方法将是可行的方法。 知道了,谢谢!我将不得不考虑是否值得为此迁移到 XSLT 3.0……希望我能接受这两个答案!

以上是关于用于在 HTML 中生成列表的 XSLT 通用模板的主要内容,如果未能解决你的问题,请参考以下文章

xml 在XSLT中生成1-10之间的随机数

xml 在XSLT中生成1-10之间的随机数

XSLT 通用解决方案,用于从 XML 中获取分层 html 表

sh 用于在git repo中生成作者列表的Bash脚本

如何在 Django 模板中生成换行符

如何在邮件模板中生成正确的 URL?