当不同的文档组对同一标签具有不同的可选标签属性时,如何最好地重用 XSLT 代码



这是场景。 我有带有如下所示的标签的 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>

现在,让我们假设属性 ab 都是可以以相同方式处理的通用属性,无论它们出现在什么元素上。 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>

相关内容

  • 没有找到相关文章