【问题标题】:Avoiding repetition in XSL templates避免 XSL 模板中的重复
【发布时间】:2019-01-03 21:30:35
【问题描述】:

我一直在使用 XML + XSL 作为生成 HTML 电子邮件的工具。由于电子邮件代码严重依赖过时的标记和内联样式,我认为最好从格式化它所需的所有疯狂中提取实际内容。

但随着我走得更远,制作更多模板,我发现我越来越多地重复自己。有没有办法让 XSL 样式表变干,或者我是否必须用表现元素堵塞我的 XML 文件?我们以这段 XML 为例:

<root>
  <headline>Hello</headline>
  <button>Click me</button>
</root>

标题和按钮周围都需要一些 html(例如 H1div),但由于我们讨论的是电子邮件,因此它们还需要一个表格单元格、一个表格行和一个表格,就像这样:

<table>
  <tr>
    <td>
      <h1>Hello</h1>
    </td>
  </tr>
</table>

<table>
  <tr>
    <td>
      <div>Hello</div>
    </td>
  </tr>
</table>

因此,天真的解决方案是在每个元素的样式表中包含该表标记,如下所示:

<xsl:template match="headline">
  <table>
    <tr>
      <td>
        <h1>
          <xsl:apply-templates/>
        </h1>
      </td>
    </tr>
  </table>
</xsl:template>

但是说在测试期间,我发现 Outlook 2007 中存在一个错误,这意味着所有这些包装表都需要一个附加属性:cell-padding=0;。如果我对表格标记进行了硬编码,我可能不得不使用几十个模板来传播该修复。

有没有办法创建包装表的“部分”模板,并在标题和按钮的各个模板中引用这些模板?

我知道我可以将标记更改为如下所示:

<root>
  <table>
    <headline>Hello</headline>
  </table>
  <table>
    <button>Click me</button>
  </table>
</root>

但这感觉就像把罐子踢到了路上。如果我发现由于 Gmail 移动应用程序中的错误,所有tds 都需要自己的特殊样式声明怎么办?那么解决方案是进入并更改标记,使其与最终输出无法区分,此时,XSL 模板真正在做什么?

我尝试了call-template 的解决方案,但没有成功。任何建议将不胜感激!

【问题讨论】:

  • 您的处理器支持哪个版本的 XSLT?
  • 我的处理器支持 XSLT 1.0,但我认为 Saxon 有一个开源处理器可以让我升级到 2.0。
  • 在 XSLT 2.0 中,您可以利用 xsl:next-match 指令。在 XST 1.0 中,您可以通过使用 mode 将模板应用到当前节点来执行类似的操作。

标签: xml xslt dry


【解决方案1】:

例如,您可以像这样合并table 模板

<xsl:template match="headline|button">
    <table cell-padding="0">
      <tr>
        <td>
          <xsl:apply-templates />
        </td>
      </tr>
    </table> 
</xsl:template>

<xsl:template match="text()[ancestor::headline]">
    <h1>
      <xsl:copy-of select="." />
    </h1>
</xsl:template>

<xsl:template match="text()[ancestor::button]">
    <div>
      <xsl:copy-of select="." />
    </div>
</xsl:template>

这会将您的两个示例模板合并为一个,稍后再将其拆分为两个不同的路径。我还添加了您的 Outlook 2007 处理。

以上模板的输出是

<table cell-padding="0">
    <tr>
        <td>
            <h1>Hello</h1>
        </td>
    </tr>
</table>
<table cell-padding="0">
    <tr>
        <td>
            <div>Click me</div>
        </td>
    </tr>
</table>

【讨论】:

  • 我担心这样的解决方案如何容忍不断变化的需求/我所处的规模(二十个组件并且还在增加)。假设按钮元素必须被包裹在一个 div 中,而不是一个 h1。有没有办法在不复制这个模板或引入一些 if/else 语句的情况下处理这个问题?感谢您的快速回复!
  • 我更新了答案以更好地处理这种情况。
  • @ErikG 请将该要求添加到您的问题中。
猜你喜欢
  • 1970-01-01
  • 2015-02-19
  • 1970-01-01
  • 2017-08-05
  • 2017-09-12
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多