【问题标题】:What are some useful constructs for using XSLT to produce XSLT?使用 XSLT 生成 XSLT 有哪些有用的构造?
【发布时间】:2009-06-04 18:12:54
【问题描述】:

我有一个现有的 XSLT 样式表,它采用 XML 并生成格式良好的 XHTML。我想制作此样式表的 XSL-FO 版本,以通过 Apache FOP 生成 PDF。我想知道的是:

我需要学习使用 xslt 模式是否方便:

  • 复制一些未更改的节点
  • 复制大部分节点,但添加额外属性

我知道我可以使用

创建新节点
<xsl:element>

但是我还需要其他有用的东西吗?请注意,虽然我没有大量从一种 XSLT 格式复制到另一种格式,但我已经通过 XSLT 完成了大量的 XML-> XHTML,因此我熟悉该语言的大部分核心。

【问题讨论】:

    标签: xml xslt xsl-fo xslt-2.0


    【解决方案1】:

    您正在寻找的模式是“修改后的身份转换”。这种方法的基础是身份转换规则,它是下面样式表中的第一个模板规则。之后的每条规则都代表复制行为的一个例外。

    <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
      <!-- By default, copy all nodes unchanged -->
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
    
      <!-- But strip out <foo> elements (including their content) -->
      <xsl:template match="foo"/>
    
      <!-- For <bar> elements, strip out start & end tags, but leave content --> 
      <xsl:template match="bar">
        <xsl:apply-templates/>
      </xsl:template>
    
      <!-- For <bat> elements, insert an attribute and append a child --> 
      <xsl:template match="bat">
        <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <xsl:attribute name="id">123</xsl:attribute>
          <xsl:apply-templates/>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    

    我对上述内容最不满意的是在最后一个模板规则中发现的重复逻辑。仅添加一个属性就需要很多代码。想象一下我们是否需要一堆这样的东西。这是另一种方法,可以让我们更精确地确定我们想要覆盖的内容:

    <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
      <!-- By default, copy all nodes unchanged -->
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <xsl:apply-templates mode="add-atts" select="."/>
          <xsl:apply-templates/>
        </xsl:copy>
      </xsl:template>
    
              <!-- By default, don't add any attributes -->
              <xsl:template mode="add-atts" match="*"/>
    
      <!-- For <bat> elements, insert an "id" attribute -->
      <xsl:template mode="add-atts" match="bat">
        <xsl:attribute name="id">123</xsl:attribute>
      </xsl:template>
    
    </xsl:stylesheet>
    

    最后,这可以更进一步,为您可能想要进行的每种编辑使用不同的模式:

    <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
      <!-- For <bat> elements, insert an "id" attribute -->
      <xsl:template mode="add-atts" match="bat">
        <xsl:attribute name="id">123</xsl:attribute>
      </xsl:template>
    
      <!-- Append <new-element/> to <bat> -->
      <xsl:template mode="append" match="bat">
        <new-element/>
      </xsl:template>
    
      <!-- Insert an element in <foo> content -->
      <xsl:template mode="insert" match="foo">
        <inserted/>
      </xsl:template>
    
      <!-- Add content before the <bar/> and <bat/> elements -->
      <xsl:template mode="before" match="bar | bat">
        <before-bat-and-bar/>
      </xsl:template>
    
      <!-- Add content only after <bat/> -->
      <xsl:template mode="after" match="bat">
        <after-bat/>
      </xsl:template>
    
      <!-- Here's the boilerplate code -->
      <!-- By default, copy all nodes unchanged -->
      <xsl:template match="@* | node()">
        <xsl:apply-templates mode="before" select="."/>
        <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <xsl:apply-templates mode="add-atts" select="."/>
          <xsl:apply-templates mode="insert" select="."/>
          <xsl:apply-templates/>
          <xsl:apply-templates mode="append" select="."/>
        </xsl:copy>
        <xsl:apply-templates mode="after" select="."/>
      </xsl:template>
    
              <!-- By default, don't add anything -->
              <xsl:template mode="add-atts" match="*"/>
              <xsl:template mode="insert"   match="*"/>
              <xsl:template mode="append"   match="*"/>
              <xsl:template mode="before"   match="@* | node()"/>
              <xsl:template mode="after"    match="@* | node()"/>
    
    </xsl:stylesheet>
    

    在 XSLT 2.0 中,由于多模式模板规则,一些样板可以稍微简化:

              <!-- By default, don't add anything -->
              <xsl:template mode="add-atts
                                  insert
                                  append
                                  before
                                  after" match="@* | node()"/>
    

    我有时会在同一个样式表中使用所有这些自定义模式,但更多时候我会根据需要懒惰地添加它们。

    【讨论】:

    • 抱歉,耽搁了一段时间。这正是我想要的(我认为)。我需要再测试一下。
    【解决方案2】:

    转换 XSLT 的最大障碍是输出名称空间前缀与转换中的实际 XSL 指令的前缀相同。如果您在 XSL 指令和输出中都使用“xsl:”,您的 XSLT 引擎将不知道它应该执行的 XSL 指令和它应该输出的 XSL 指令之间的区别,因此您的 XSLT 不会解析。也就是说,除非您使用命名空间别名:

    <xsl:namespace-alias stylesheet-prefix="x" result-prefix="xsl"/>
    

    此指令位于&lt;xsl:stylesheet /&gt; 内,允许您使用替代命名空间前缀在转换中编写结果标记。稍后,当创建输出文档时,您实际需要的前缀将被插入到别名的位置。因此,例如,这是一个在输出文档中生成模板的模板:

    <xsl:template match="xsl:template[@match='title']>
       <x:template match="title>
          <x:apply-templates />
       </x:template>
    </xsl:template>
    

    这是一篇好文章:http://www.xml.com/pub/a/2001/04/04/trxml/

    【讨论】:

    【解决方案3】:

    过去我开发了 XSL-FO 样式表,然后使用Render-X FO2HTML stylesheet 将 XSL-FO 转换为 HTML。它将&lt;block&gt;元素转换为&lt;div&gt;&lt;inline&gt;转换为&lt;span&gt;等。

    我以前没用过,但你可以考虑试试HTML2FO stylesheets。或者至少查看他们以借用一些想法。

    由于 HTML 缺少 FO 提供的一些分页结构,它可能无法为您提供 XSL-FO 输出所需的全部内容,但可能可以处理从 HTML 到 XSL-FO 元素的大部分转换逻辑/文档正文中的属性。

    【讨论】:

      猜你喜欢
      • 2014-12-30
      • 1970-01-01
      • 2017-12-29
      • 2011-02-14
      • 2014-08-17
      • 2010-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多