以下是该方案。我有XML文档,标签看起来像这样:
<para a="A" b="B" c="C">
出现在不同类的XML文档中。 a和b属性是完全通用的,并且在所有文档中的处理方式完全相同。可选的c属性取决于文档类,并且需要不同的转换,具体取决于文档类。我想编写一个样式表,将 include d或 import 编辑到特定于文档类的样式表中,这些样式表负责转换和属性 a 和 b ,属性c由父样式表处理。我至少可以想到几种方法,但我想知道是否有一些规范的最佳方式。
让我们调用样式表来共享 st-generic.xsl 。 st-generic.xsl中的每个模板都将命名为:
<xsl:template match="para" name="generic-para">...</xsl:template>
然后,特定于文档类的样式表将导入st-generic.xsl(而不是include,以设置优先级),并包含如下所示的模板:
<xsl:template match="para">
<xsl:call-template name="generic-para"/>
{other stuff}
<xsl:apply-templates/>
</xsl:template>
这可能有效,但似乎有点不雅。例如,在大多数情况下,只需要 generic-para 模板,因此该模板需要同样包含
<xsl:apply-templates/>
模板体中的节点。我想知道是否有更好的方法来做到这一点?
答案 0 :(得分:2)
如果没有看到更多的代码和输入,我不明白为什么你应该使用命名模板。
让我们考虑一下你输入中的两个假设元素:
<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>
所有这些代码仍然在单独的模板中,可以模块化,导入或随意包含。
答案 1 :(得分:1)
目前我能想到的最好的是:
将此内容包含在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
模板专注于自定义行为。
答案 2 :(得分:0)
XSL提供了一种使用&lt; xsl:apply-imports /&gt; 元素解决此问题的规范方法。
在此特定示例中,您可以使用 st-generic.xsl 样式表导入 customizations.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导入另一个样式表,调用命名模板根据需要或使用上一个示例中使用的&lt; xsl:apply-imports /&gt; 。
答案 3 :(得分:0)
所以,我的原始答案证明不起作用,因为&lt; xsl:apply-imports /&gt;的不幸方式在没有匹配模板时有效。 See the answer to this question for details.最重要的是它会转向默认模板,当你按照我在原始答案中使用的方式使用它时,最终会弄乱输出。
在思考如何处理这个问题时,我想出了一个我更喜欢的替代解决方案,即使用包含的样式表中定义的属性集。例如,要处理原始问题中提出的案例,您可以执行以下操作:
主样式表如下所示:
<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>
generic-attributes.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>