用于在 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.
这里很重要:
非空集合的测试应该在通用模板中,因为我不想用条件包装对这个模板的每次调用,我不想输出当集合为空时清空 <ul>
个元素。
在我正在转换的 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>
元素。
我想编写一些通用模板来将节点集合转换为 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.
这里很重要:
非空集合的测试应该在通用模板中,因为我不想用条件包装对这个模板的每次调用,我不想输出当集合为空时清空
<ul>
个元素。在我正在转换的 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>
元素。