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

XSLT generic template to generate lists in HTML

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

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

连同与选择中的各个元素相匹配的模板,生成的 HTML 应该类似于

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

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

我尝试了以下方法:

<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>

但这行不通:集合中的每个元素都会单独成为<ul>。从概念上讲,我想要的是一种将 集合本身 转换为 <ul>,然后将集合的 元素 转换为个人 <li>s.

这里很重要:

  1. 非空集合的测试应该在通用模板中,因为我不想用条件包装对这个模板的每次调用,我不想输出当集合为空时清空 <ul> 个元素。

  2. 在我正在转换的 XML 文档中,集合中的元素通常没有共同的父元素。这意味着我无法将父对象转换为 <ul> 并将其子对象转换为 <li>;源文档中没有对应于 <ul>.

    的元素

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

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

    <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 中的每个元素之前围绕所选节点创建一个 ul 包装器(我认为,你称之为 集合 ).


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

在 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>

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