如何避免XSL转换中的重复?

时间:2015-11-17 12:37:37

标签: xml xslt code-duplication

在我们的应用程序中,需要处理以下结构的XML文档(大大简化):

<FooBar>
  <Foo ID="attr.1">value1</Foo>
  <Foo ID="attr.2">another value</Foo>
  <Bar ID="attr.3">
    <Foo>1</Foo>
    <Foo>2</Foo>
  </Bar>
</FooBar>

使用2种不同的转换处理这些文档。这两种转换主要针对Foo元素以及上面示例中未显示的一些支持信息。第一个转换输出csv,其中Foo元素被转换为它自己的行。另一个转换仅将Foo元素输出为逗号分隔列表。

第一次转换的示例输出是:

attr.1-0;attr.1;value1
attr.2-0;attr.2;another value
attr.3-0;attr.3;1
attr.3-1;attr.3;2

第二次转换的示例输出是:

attr.1-0,attr.2-0,attr.3-0,attr.3-1

比较两种转换时,它们共享大约75%的代码。实际上,唯一的区别是实际用于输出文本的命名模板。

转换如下所示:

<xsl:template match="/">
  <!-- output some header information -->
  <xsl:apply-templates select="Foo" />
  <xsl:apply-templates select="Bar" />
</xsl:template>
<xsl:template match="Bar">
  <!-- here is also some stuff -->
  <xsl:apply-templates select="Foo" />
</xsl:template>
<xsl:template match="Foo" >
  <!-- output the text that is special to transformation 1 or 2 -->
</xsl:template>

如何防止这两种转换中的代码重复?

2 个答案:

答案 0 :(得分:1)

解决方案只是将整个代码重新组织为一些新文件。

我缺少的一点是,如果链接到样式表定义了一个与链接样式表中调用的名称相同的模板,则样式表可以链接到不同的其他样式表。

现在每个转换都有一个根样式表。这将包括一个包含共享模板的样式表和一个包含转换特殊模板的样式表。

所以这看起来像:

transformation1-root.xsl

<xsl:include href="transformation-shared.xsl" />
<xsl:include href="transformation1-specific.xsl" />
<xsl:template match="/">
  <xsl:call-template name="templateFooBarRoot" />
</xsl:template>

transformation2-root.xsl

<xsl:include href="transformation-shared.xsl" />
<xsl:include href="transformation2-specific.xsl" />
<xsl:template match="/">
  <xsl:call-template name="templateFooBarRoot" />
</xsl:template>

transformation-shared.xsl

<xsl:template name="templateFooBarRoot">
  <!-- output some header information -->
  <xsl:apply-templates select="Foo" />
  <xsl:apply-templates select="Bar" />
</xsl:template>
<xsl:template match="Bar">
  <!-- here is also some stuff -->
  <xsl:apply-templates select="Foo" />
</xsl:template>
<xsl:template match="Foo" >
  <xsl:call-template name="transformationSpecificTemplate" />
</xsl:template>

transformation1-specific.xsl

<xsl:template name="transformationSpecificTemplate">
<!-- stuff specific to transformation 1 -->
</xsl:template>

transformation2-specific.xsl

<xsl:template name="transformationSpecificTemplate">
<!-- stuff specific to transformation 2 -->
</xsl:template>

答案 1 :(得分:1)

这是传递策略的一种非常通用的方法(类似于函数式编程语言和XSLT 3.0中的高阶函数)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:t1="my:t1" xmlns:t2="my:t2" >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pStrategy" select="'t1:'"/>

 <t1:strategy/>
 <t2:strategy/>

 <xsl:variable name="vStrategy" select="document('')/*/*[starts-with(name(), $pStrategy)]"/>

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*">
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

 <xsl:template match="t1:strategy">
   <xsl:param name="pNum"/>
   <xsl:value-of select="2*$pNum"/>
 </xsl:template>

 <xsl:template match="t2:strategy">
   <xsl:param name="pNum"/>
   <xsl:value-of select="$pNum*$pNum"/>
 </xsl:template>

 <xsl:template match="num/text()">
   <xsl:apply-templates select="$vStrategy">
     <xsl:with-param name="pNum" select="."/>
   </xsl:apply-templates>
 </xsl:template>
</xsl:stylesheet>

对以下XML文档应用此转换时:

<nums>
  <num>01</num>
  <num>02</num>
  <num>03</num>
  <num>04</num>
  <num>05</num>
  <num>06</num>
  <num>07</num>
  <num>08</num>
  <num>09</num>
  <num>10</num>
</nums>

策略&#34; t1&#34;执行,结果包含每个原始数字加倍

<nums>
   <num>2</num>
   <num>4</num>
   <num>6</num>
   <num>8</num>
   <num>10</num>
   <num>12</num>
   <num>14</num>
   <num>16</num>
   <num>18</num>
   <num>20</num>
</nums>

当转换的调用者为全局参数$ pStrategy提供值&#39; t2:&#39;,然后策略&#34; t2&#34;执行,结果包含每个原始数字平方

<nums>
   <num>1</num>
   <num>4</num>
   <num>9</num>
   <num>16</num>
   <num>25</num>
   <num>36</num>
   <num>49</num>
   <num>64</num>
   <num>81</num>
   <num>100</num>
</nums>

可以阅读更多关于这种强大技术的信息,这是the FXSL library在XSLT 1.0和2.0 herehere 中进行函数式编程的基础。< / p>