这是场景。 我有带有如下所示的标签的 XML 文档:
<para a="A" b="B" c="C">
出现在不同类别的 XML 文档中。 a 和 b 属性是完全通用的,在所有文档中的处理方式完全相同。 可选的 c 属性依赖于文档类,并且需要不同的转换,具体取决于文档类。 我想编写一个样式表来包含d或导入ed到特定于文档类的样式表中,该样式表负责对a和b进行转换,这些样式表的属性c由父样式表处理。 我至少可以想到几种方法来做到这一点,但我想知道是否有一些规范的最佳方法。
让我们将样式表称为共享 st-generic.xsl。 st-generic.xsl 中的每个模板都将被命名为:
<xsl:template match="para" name="generic-para">...</xsl:template>
然后,特定于文档类的样式表将导入 st-generic.xsl(而不是包含,以设置优先级),并将包含如下所示的模板:
<xsl:template match="para">
<xsl:call-template name="generic-para"/>
{other stuff}
<xsl:apply-templates/>
</xsl:template>
这可能有效,但似乎有点不优雅。例如,在大多数情况下,只需要 generic-para 模板,因此此模板需要类似地包含
<xsl:apply-templates/>
节点。 我想知道是否有更好的方法来做到这一点?
如果没有看到更多的代码和输入,我不明白为什么要使用命名模板。
让我们考虑输入中的两个假设元素:
<para a="A" b="B" c="C">paracontent</para>
<div a="A" b="B" c="C">divcontent</div>
现在,让我们假设属性 a
和 b
都是可以以相同方式处理的通用属性,无论它们出现在什么元素上。 c
以多种方式处理,具体取决于父元素。
当然有一个para
元素匹配的模板
<xsl:template match="para">
我不明白为什么你需要一个命名模板来处理这个元素的属性。为什么不简单地apply-templates
所有属性?
<xsl:template match="para">
<xsl:apply-templates select="@*"/>
<!--Do stuff other than processing attributes...-->
</xsl:template>
然后,其他模板(未命名模板)将匹配两个通用属性:
<xsl:template match="@a">
<!--Process attribute a, no matter the parent element-->
</xsl:template>
和
<xsl:template match="@b">
<!--Process attribute b, no matter the parent element-->
</xsl:template>
甚至可能
<xsl:template match="@a|@b">
<!--Process attributes a or b, no matter the parent element-->
</xsl:template>
而您将为属性c
编写单独的模板:
<xsl:template match="para/@c">
<!--Process attribute c, if para is the parent-->
</xsl:template>
和
<xsl:template match="div/@c">
<!--Process attribute c, if div is the parent-->
</xsl:template>
所有这些代码仍然在单独的模板中,可以模块化和导入或随意包含。
目前我能想到的最好的是:
将此包含在您的 st-generic.xsl 文件中:
<xsl:template match="para">
{ do para processing }
<xsl:apply-templates select="para" mode="custom" />
<xsl:apply-templates />
</xsl:template>
<xsl:template match="para" mode="custom" priority="-5" />
然后,当您需要自定义行为时,可以将其放在主模板中:
<xsl:template match="para" mode="custom">
{ do custom para processing }
</xsl:template>
这将在泛型文件中的{ do para processing }
和<xsl:apply-templates />
之间调用,因此您可以让custom
模板专注于自定义行为。
XSL 提供了一种使用 <xsl:apply-imports> 元素解决此问题的规范方法。
在此特定示例中,您将让 st-generic.xsl 样式表导入一个 customs.xsl 样式表,其中包括可选的自定义项:
st-generic.xsl:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="customizations.xsl"/>
<xsl:template match="para">
<xsl:if test="@a and string(@a)">
{do stuff}
</xsl:if>
<xsl:if test="@b and string(@b)">
{do other stuff}
</xsl:if>
<xsl:apply-imports/>
<xsl:apply-templates/>
</xsl:template>
/xsl:stylesheet>
customizations.xsl:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="para">
<xsl:if test="@c and string(@c)">
{do special stuff}
</xsl:if>
</xsl:template>
/xsl:stylesheet>
如果您还在 st-generic.xsl 样式表中命名模板,则可以提供一个完全灵活的解决方案,然后允许您将 st-generic.xsl 导入到另一个样式表中,根据需要调用命名模板或使用 <xsl:apply-imports> 如上一个示例中使用的那样。
因此,我最初的答案被证明不起作用,因为当没有匹配的模板时,<xsl:apply-imports> 的工作方式很不幸。 有关详细信息,请参阅此问题的答案。 最重要的是,它诉诸默认模板,当您按照我在原始答案中的方式使用它时,最终会弄乱输出。
在思考如何处理这个问题时,我想出了一个我更喜欢的替代解决方案,即使用包含在样式表中定义的属性集。 例如,要处理原始问题中提出的案例,您可以执行以下操作:
主样式表如下所示:
<xsl:include href="generic-attributes.xsl"/>
<xsl:template match="para">
<fo:block xsl:use-attribute-sets="para_default-attrs">
<xsl:if test="@a and string(@a)">
{do stuff}
</xsl:if>
<xsl:if test="@b and string(@b)">
{do other stuff}
</xsl:if>
~~ other stuff ~~
<xsl:apply-templates/>
</fo:block>
</xsl:template>
然后,泛型属性.xsl 文件将包含以下内容:
<xsl:attribute-set name="para_default-attrs">
<xsl:attribute name="a">A</xsl:attribute>
<xsl:attribute name="b">B</xsl:attribute>
</xsl:attribute-set>