查看源码 类似 XSLT 的转换
示例
示例 1 使用 xslapply
原始 XSLT
<xsl:template match="doc/title">
<h1>
<xsl:apply-templates/>
</h1>
</xsl:template>
在 Erlang 中变为
template(E = #xmlElement{ parents=[{'doc',_}|_], name='title'}) ->
["<h1>",
xslapply(fun template/1, E),
"</h1>"];
示例 2 使用 value_of 和 select
<xsl:template match="title">
<div align="center"><h1><xsl:value-of select="." /></h1></div>
</xsl:template>
变为
template(E = #xmlElement{name='title'}) ->
["<div align=\"center\"><h1>", value_of(select(".", E)), "</h1></div>"];
示例 3 简单的 xsl 样式表
一个完整的示例,其中 XSLT 样式表在 xmerl 发行版中。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/TR/xhtml1/strict">
<xsl:strip-space elements="doc chapter section"/>
<xsl:output
method="xml"
indent="yes"
encoding="iso-8859-1"
/>
<xsl:template match="doc">
<html>
<head>
<title>
<xsl:value-of select="title"/>
</title>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="doc/title">
<h1>
<xsl:apply-templates/>
</h1>
</xsl:template>
<xsl:template match="chapter/title">
<h2>
<xsl:apply-templates/>
</h2>
</xsl:template>
<xsl:template match="section/title">
<h3>
<xsl:apply-templates/>
</h3>
</xsl:template>
<xsl:template match="para">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="note">
<p class="note">
<b>NOTE: </b>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="emph">
<em>
<xsl:apply-templates/>
</em>
</xsl:template>
</xsl:stylesheet>
示例 4 Erlang 版本
前一个示例的 Erlang 转换
-include("xmerl.hrl").
-import(xmerl_xs,
[ xslapply/2, value_of/1, select/2, built_in_rules/2 ]).
doctype()->
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\
\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd \">".
process_xml(Doc)->
template(Doc).
template(E = #xmlElement{name='doc'})->
[ "<\?xml version=\"1.0\" encoding=\"iso-8859-1\"\?>",
doctype(),
"<html xmlns=\"http://www.w3.org/1999/xhtml\" >"
"<head>"
"<title>", value_of(select("title",E)), "</title>"
"</head>"
"<body>",
xslapply( fun template/1, E),
"</body>"
"</html>" ];
template(E = #xmlElement{ parents=[{'doc',_}|_], name='title'}) ->
["<h1>",
xslapply( fun template/1, E),
"</h1>"];
template(E = #xmlElement{ parents=[{'chapter',_}|_], name='title'}) ->
["<h2>",
xslapply( fun template/1, E),
"</h2>"];
template(E = #xmlElement{ parents=[{'section',_}|_], name='title'}) ->
["<h3>",
xslapply( fun template/1, E),
"</h3>"];
template(E = #xmlElement{ name='para'}) ->
["<p>", xslapply( fun template/1, E), "</p>"];
template(E = #xmlElement{ name='note'}) ->
["<p class=\"note\">"
"<b>NOTE: </b>",
xslapply( fun template/1, E),
"</p>"];
template(E = #xmlElement{ name='emph'}) ->
["<em>", xslapply( fun template/1, E), "</em>"];
template(E)->
built_in_rules( fun template/1, E).
如果您希望在“推送”转换中写入任何文本,则必须以调用 xmerl_xs:built_in_rules/2
结束。这些是大量使用 xslapply( fun template/1, E )
而不是 value_of(select("xpath",E))
的转换,后者是拉取...
最大的示例是将本文档从简化 Docbook XML 格式转换为 xhtml 的样式表。源文件是 sdocbook2xhtml.erl。
技巧和窍门
for-each
for-each 函数在 XSLT 样式表中非常常见。它通常可以重写并替换为 select/1。由于 select/1 返回一个 #xmlElements 列表,而 xslapply/2 遍历它们,因此它或多或少等同于循环遍历所有元素。
position()
XSLT 的 position() 和 #xmlElement.pos 不是相同的。必须在 Erlang 中创建自己的位置。
示例 5 计算位置
<xsl:template match="stanza">
<p><xsl:apply-templates select="line" /></p>
</xsl:template>
<xsl:template match="line">
<xsl:if test="position() mod 2 = 0">  </xsl:if>
<xsl:value-of select="." /><br />
</xsl:template>
可以写成
template(E = #xmlElement{name='stanza'}) ->
{Lines,LineNo} = lists:mapfoldl(fun template_pos/2, 1, select("line", E)),
["<p>", Lines, "</p>"].
template_pos(E = #xmlElement{name='line'}, P) ->
{[indent_line(P rem 2), value_of(E#xmlElement.content), "<br />"], P + 1 }.
indent_line(0)->"  ";
indent_line(_)->"".
全局树感知
在 XSLT 中,您可以使用 XPath 对树的顶部进行“根”访问,即使您位于树的深处。
xslapply/2 函数仅将树的子部分带回模板 fun。但是,编写可以同时处理子树和顶层树的模板 fun 非常容易。
示例 6 传递根树
以下示例片段会将文章标题添加到任何节标题之前
template(E = #xmlElement{name='title'}, ETop ) ->
["<h3>", value_of(select("title", ETop))," - ",
xslapply( fun(A) -> template(A, ETop) end, E),
"</h3>"];