使用 XSLT 转换属性
模板非常适用于把样式表分割成较小的、可管理的单元。模板的另一个好处是,处理器可以根据匹配条件自动选择最适当的模板。多数模板都匹配元素,但是正如 Benoit Marchal 在这篇技巧中所说明的那样,模板同样可以匹配属性。
类和方法是面向对象程序员的工具,用于把大型应用程序组织成较小的、更加可管理的单元。XSLT 程序员为了同样的目的使用模板。当模式和当前节点匹配时,处理器就把控制交给模板。
这种模式匹配机制特别适用于处理树状结构(如 XML 文档)。从而形成了声明性的编程风格,因为避免了编写所有的树遍历和树处理例程。相反,由处理器遍历输入文档并自动为节点选择最合适的模板。
当不知道元素在输入文档中的出现顺序或者是否重复时,模式匹配特别方便。同样,处理器负责重复调用模板解决重复问题。
测试属性
多数模板都是为匹配元素而编写的。当样式表处理属性时,规则通常附加在匹配元素的模板中,如清单 1 所示(本文中的所有例子都摘自 DocBook-to-HTML 样式表):
清单 1. 处理附加在元素中的属性
<xsl:template match="ulink">
<a href="{@url}"><xsl:apply-templates/></a>
</xsl:template>
|
这个模板转换 ulink 元素和 url 属性,但只与 ulink 元素匹配。
如果属性是必需的——换句话说,它一定会出现,则对元素匹配是合理的。但是如果属性是可选的,您就得在输出中生成某些内容 之前 测试该属性是否存在。有些情况下,希望通过模式中的条件进行测试,比如清单 2:
清单 2. 在模板匹配中测试属性
<xsl:template match="emphasis[@type='bold']">
<b><xsl:apply-templates/></b>
</xsl:template>
|
匹配属性
测试属性并不总是可行的。看一看 DocBook 中图片 imagedata 的标记。 imagedata 有可选的 width 和 depth 属性可能需要保存到 HTML 中。对所有可能的组合编码太困难了( imagedata[@width] , imagedata[@depth] 和 imagedata[@width and @depth] ——就是说仅仅为了 两个 属性要使用三个模板)。更合理的办法是让处理器遍历属性节点并针对属性节点编写模板,如清单 3 所示:
清单 3. 匹配属性的模板
<xsl:template match="imagedata">
<img><xsl:apply-templates select="@*"/></img>
</xsl:template>
<xsl:template match="@width">
<xsl:attribute name="width">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="@depth">
<xsl:attribute name="height">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="@fileref">
<xsl:attribute name="href">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
|
注意,处理器默认是不遍历属性节点的。必须使用 select="@*" 属性明确地要求这样做。
匹配元素的模板和匹配属性的模板有两个重要的区别:
- 属性是叶子。
xsl:apply-templates 指令什么地方也去不了,因为属性没有子女可供处理器遍历。应该使用 xsl:value-of 。
- 输入中的多数属性在输出中仍然是属性。使用
xsl:attribute 向输出树中插入属性。但是要小心,因为 xsl:attribute 必须出现在其他任何子女之前。换句话说, xsl:apply-templates 指令必须在调用者的任何文本或子元素之前使用。
模板没有限制
匹配属性赋予您完整的 XSLT 表达能力。模板并不仅限于把属性转换成另一个属性。可以向模式中增加条件或者把属性转换成元素。清单 4 中的模板定义了一个特殊的规则,以匹配 fileref 作为 videodata 的一个属性。它创建的是一个元素而非属性。
清单 4. 匹配带条件的属性
<xsl:template match="videodata/@fileref">
<param name="src" value="{.}"/>
</xsl:template>
|
此外,还可以在调用者中通过 select="@* | node()" 属性把模板应用于属性和元素内容,如清单 5 所示:
清单 5. 调用模板处理元素和属性
<xsl:template match="para">
<p><xsl:apply-templates select="@* | node()"/></p>
</xsl:template>
|
这个技巧是 XSLT 编码中更一般原则的实际例子:为了使样式表更加可维护,把工作分到几个模板中是值得的。
标题: 使用 XSLT 转换属性
关键字:属性 转换 模板 匹配 元素 match 处理器 select
|