使用XSLT生成XSLT的一些有用结构是什么?

3
我有一个现成的XSLT样式表,它可以将XML转换为格式良好的XHTML。我想创建一个基于XSL-FO的样式表,通过Apache FOP生成PDF。我想知道的是:
是否有方便易用的xslt模式,能够实现以下功能:
1.复制某些节点而不进行修改
2.复制大部分节点,并添加额外的属性
我知道我可以使用来创建新节点。
<xsl:element>

但是,我是否需要其他有用的东西?请注意,虽然我没有在不同的XSLT格式之间进行大量复制,但我已经通过XSLT进行了大量的XML -> XHTML转换,因此我熟悉该语言的大部分核心内容。

3个回答

8
你要寻找的模式是“修改后的身份转换”。这种方法的基础是身份转换规则,也就是下面样式表中的第一个模板规则。之后的每个规则都代表了对复制行为的例外情况。
<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()"/>

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


抱歉让你等了一会儿。这正是我想要的(我想)。我需要再进行一些测试。 - Jay Stevens

3

将XSLT转换的最大障碍是输出命名空间前缀与实际XSL指令相同。如果您在XSL指令和输出中都使用“xsl:”,则您的XSLT引擎将无法区分应执行的XSL指令和应输出的指令,因此您的XSLT将无法解析。除非您使用命名空间别名:

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

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

<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/


好的,xslt 有一个“另一个 xslt 命名空间”,您也可以使用它! - alamar
1
http://www.w3.org/1999/XSL/Transform 是一个普通的命名空间,而 http://www.w3.org/1999/XSL/TransformAlias 是另一个。 - alamar

0

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

我以前没有使用过它们,但您可以考虑尝试HTML2FO样式表。或者至少查看它们以借鉴一些想法。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接