xslt元素的使用
当您听到样式表一词时,您可能会想到CSS样式表。 XSLT样式表通常用于XML转换,例如Web服务之间的数据映射。 因为XSLT非常适合此目的,所以创建了顶级元素<stylesheet>
的<xsl:transform>
别名-尽管很少使用。 这种XSLT转换的输入结构与输出完全不同。 首先,名称空间是不同的。
相反,XSLT样式表的输入结构与输出结构相似,但更为简单。 一些标签得到了丰富,但是大多数标签被简单地复制而不改变输出。 输入和输出名称空间是相同的(HTML)。 输入文档还可能包含样式表的指令(例如创建脚注),该指令属于另一个名称空间,并且不会到达输出中。
在本文中,学习如何使用XSLT样式表来丰富XHTML文档。 本文中的示例显示了如何使用指令,如何引用其他源文档的各个部分以及如何使用主文档中的链接进行导航。 另外,探索页面解释和编译之间的区别。
CSS样式表的局限性
XSLT样式表不会阻止您使用其他技术,例如JavaScript或CSS。 CSS适用于字体,重点,颜色,边距等。 它不是用于组合来自不同位置的信息(例如脚注,模块)或生成目录。 这就是XSLT发挥作用的地方-它正在完成而不是替换CSS。
XSLT可以做什么的示例
实际上,您可以将XSLT代码收集在一个文件中。 为简单起见,本文中的每个示例均位于单独的XSLT文件中,但始终需要某些代码。 清单1显示了所需的代码。
清单1.所需代码(在samples / common.xml中)
<s:stylesheet
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:a="http://sourceforge.net/projects/arbalo/"
xmlns:s="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="a h"
version="1.0"
>
<s:template match="h:head">
<s:copy>
<s:apply-templates select="@*|node()"/>
<meta
http-equiv="content-type"
content="text/html;charset=UTF-8" />
<link
href="common.css"
rel="stylesheet"
type="text/css" />
</s:copy>
</s:template>
<s:template match="*">
<s:copy>
<s:copy-of select="@*"/>
<s:apply-templates/>
</s:copy>
</s:template>
</s:stylesheet>
XHTML的命名空间定义了两次:default和h:
默认名称空间用于编写输出XHTML标记,应避免使用名称空间前缀。 h:
在XPath表达式中使用。
本文使用XSLT 1.0版。 目前,大多数浏览器无法解释XSLT 2.0。 但是,如果XSLT在服务器上运行,则它可能是一个可用的选项。 XSLT 2.0还提供:
- XPATH 2.0(
if…then…else
和许多内置函数) - 内置和用户编写的XPATH函数
- 分组
在清单1中 :
-
s:template match="head"
通过添加指向CSS样式表的链接来丰富源文档的head部分。 即使UTF-8是XML的默认编码,某些浏览器也需要内容类型来呈现它。 -
s:template match="*"
是默认的深层副本。 原则上,所有内容都会复制到目标文档中。 如果缺少此模板,则仅将标签的文本内容复制到目标文档。 处理指令节点未复制。
本文中的所有其他示例是导入common.xsl的单独文件。
丰富
通过扩充功能,添加了源文档中未明确要求的功能。 一个示例是清单1中 CSS样式表的链接。 尝试另一个示例,在每个内部链接上添加一个小箭头(^ v),指示目标是在目标之前还是之后。 清单2显示了样式表。
清单2.样式表(在samples / linkUpDown.xsl中)
<s:stylesheet
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:s="http://www.w3.org/1999/XSL/Transform"
version="1.0"
>
<s:import href="common.xsl"/>
<s:template match="h:a[starts-with(@href,'#')]">
<s:copy>
<s:copy-of select="@*"/>
<s:variable name="name" select="substring-after(@href,'#')"/>
<s:choose>
<s:when test="preceding::h:a[@name=$name]">
<s:text>^</s:text>
</s:when>
<s:when test="following::h:a[@name=$name]">
<s:text>v</s:text>
</s:when>
</s:choose>
<s:apply-templates/>
</s:copy>
</s:template>
</s:stylesheet>
首先,导入清单2中的通用样式表。 模板匹配内部链接(以'#'
开头)。 如果链接所指向的锚点位于链接之前,则该链接将由向上的箭头(或如果相反的情况为真,则由向下的箭头)丰富。
s:copy-of
和s:apply-templates
确保没有任何障碍。
清单3显示了带有内部链接的示例文档,清单2中的样式表丰富了该示例文档。
清单3.源文档(在samples / linkUpDown.xml中)
<?xml-stylesheet href="linkUpDown.xsl" type="text/xsl"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head/>
<body>
<a name="a"/>
<p>This link goes <a href="vb">downward.</a></p>
<br/>
<p>Reduce the size of the window to verify the link really works.</p>
<br/>
<a name="b"/>
<p>This link goes <a href="^a">upward.</a>
</p>
</body>
</html>
除了清单4中的条目外,目标文档看起来相同。
清单4.目标文档(在samples / linkUpDown.html中)
… <a href="#b">v downwards.</a> …
… <a href="#a">^ upwards.</a> …
指令
您可以在源文档中插入指示样式表要执行的指令。 它们属于另一个名称空间(在示例中为前缀a:
:),并且不会复制到目标文档中。
在清单5中,脚注由指令标记a:ref
在源文档中的任何位置创建。
清单5.样式表(在samples / footnote.xsl中)
<s:stylesheet
xmlns="http://www.w3.org/1999/xhtml"
xmlns:a="http://sourceforge.net/projects/arbalo/"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:s="http://www.w3.org/1999/XSL/Transform"
version="1.0"
>
<s:import href="common.xsl"/>
<s:template match="h:body">
<s:copy>
<s:apply-templates select="@*|node()"/
<!-- put the footnotes at the end
if there is no a:references directive -->
<s:if test="not(descendant::a:references)">
<s:call-template name="references"/>
</s:if>
</s:copy>
</s:template>
<s:template match="a:ref">
<s:variable
name="number"
select="count(preceding::a:ref) + 1"/>
<a name="ref-{$number}"></a>
<a class="footnote" href="#reference-{$number}">
<s:value-of select="concat('v ',$number)"/>
</a>
</s:template>
<!-- if a:reference is missing, assume it at the end of the body -->
<s:template match="a:references" name="references">
<hr/>
<s:for-each select="//a:ref">
<s:variable name="number" select="count(preceding::a:ref) + 1"/>
<p>
<a name="reference-{$number}"></a>
<a class="footnote" href="#ref-{$number}">
<s:value-of select="concat(' ^',$number)"/>
</a>
<s:apply-templates/>
</p>
</s:for-each>
</s:template>
</s:stylesheet>
通过源文档中的a:references
指令,名为references
的模板在模板与指令匹配的位置分配脚注。 如果这样的指令,则第一模板匹配body
分配在末尾的脚注body
通过调用相同的模板命名references
。 在这两种情况下,脚注的内容均被列出,并生成向上的链接并由向上的箭头指示。
与a:ref
匹配的第二个模板使用向下箭头创建到脚注的链接。 脚注已编号。 在此忽略其内容。
XSLT转换后,通过CSS样式表解析class="footnote"
属性,该样式表链接在XSLT样式表common.xsl中。
清单6中的源文档使用a:ref
指令创建脚注。
清单6.源文档(在samples / footnote.xml中)
<?xml-stylesheet href="footnote.xsl" type="text/xsl"?>
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:a="http://sourceforge.net/projects/arbalo/"
>
<head/>
<body>
<p>
This example looks a little scientific
<a:ref>
From Latin
<em>scientia</em>
</a:ref>
and academic
<a:ref>From Greek akademia</a:ref>.
</p>
<p>
Do you know why?
<a:ref>
It uses
<em>footnotes</em>.
</a:ref>
</p>
<p>Reduce size of window to verify links are generated.</p>
</body>
</html>
目标文档在底部包含脚注列表,如清单7所示。
清单7.目标文档(在samples / footnote.html中)
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:a="http://sourceforge.net/projects/arbalo/">
<head><link type="text/css" rel="stylesheet" href="common.css"/></head>
<body>
<p>This example looks a little scientific
<a name="ref-1"/><a href="#reference-1" class="footnote">v 1</a>
and academic.
<a name="ref-2"/><a href="#reference-2" class="footnote">v 2lt;/a>
</p>
<p>Do you know why?
<a name="ref-3"/><a href="#reference-3" class="footnote">v 3</a>
</p>
<p>Reduce size of window to verify links are generated.</p>
br/><br/>
<hr/>
<p><a name="reference-1"/><a href="#ref-1" class="footnote"> ^1</a>
From Latin
<em>scientia</em>
</p>
<p><a name="reference-2"/>
<a href="#ref-2" class="footnote"> ^2</a>From Greek akademia</p>
<p><a name="reference-3"/><a href="#ref-3" class="footnote"> ^3</a>
It uses
<em>footnotes</em>.
</p>
</body>
</html>
越过源文档的边界
也可以引用其他源文档的一部分。 a:include
指令包含一个元素,该元素可能属于另一个源文档并对其进行转换,如清单8所示。
清单8.样式表(在samples / include.xsl中)
<s:stylesheet
xmlns="http://www.w3.org/1999/xhtml"
xmlns:a="http://sourceforge.net/projects/arbalo/"
xmlns:s="http://www.w3.org/1999/XSL/Transform"
version="1.0"
>
<s:import href="common.xsl"/>
<s:template match="a:include">
<s:choose>
<s:when test="0!=string-length(@src)">
<s:apply-templates
select="document(@src)//*[@id=current()/@refid]"/>
</s:when>
<s:when test="not(@src) and //a:default[1]/@src">
<s:apply-templates
select="document(//a:default[1]/@src)//*[@id=current()/@refid]"/>
</s:when>
<s:when test="0=string-length(@src) or not(//a:default[1]/@src)">
<s:apply-templates
select="//*[@id=current()/@refid]"/>
</s:when>
</s:choose>
</s:template>
</s:stylesheet>
源文档中的a:include
指令引用源元素的id
。 包含元素的文档可以在src
属性中命名。 如果缺少该属性,则使用a:default
指令的src
属性。 如果任何地方都没有src
属性,则使用相同的源文档。 因此, refid
引用了id
以避免无限递归。
导入的元素可能是复杂类型,并且在包含之后进行转换( apply-templates
)。 清单9,清单10和清单11显示了示例。
清单9.源文档(在samples / include.xml中)
<?xml-stylesheet href="include.xsl" type="text/xsl"?>
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:a="http://sourceforge.net/projects/arbalo/">
<head>
<a:default src="includedY.xml"/>
</head>
<body>
<p>The following text is included:</p>
<a:include refid="x" src="includedX.xml"/>
<a:include refid="y1"/>
<p id="i">double</p>
<a:include refid="y2"/>
<a:include refid="i" src=""/>
</body>
</html>
清单10.部分源文档(在samples / includeY.xml中)
<h2 id="y2">I'm the <em>included</em> h2</h2>
<h1 id="y1">I'm the <em>included</em> h1</h1>
清单11.目标文档(在samples / include.html中)
<body>
<p>The following text is included:</p>
<p id="x">I'm the <em>included</em> paragraph.</p>
<h1 id="y1">I'm the <em>included</em> h1</h1>
<p id="i">double</p>
<h2 id="y2">I'm the <em>included</em> h2</h2>
<p id="i">double</p>
</body>
</html>
主文件和导航
假设您有一个由几个页面组成的演示文稿,并且一个主文档包含页面标题及其链接。 您可以生成完整的导航-从每个页面到任何其他页面,以及到上一页和下一页。 这些详细信息超出了本文的范围,但是“ 相关主题”提供了使用主文档HTML演示文稿的链接。 您可以通过将.xml替换为.html来获得编译后的版本。 让浏览器为您显示.xml的简洁源代码。 您会惊讶于产生了多少。
解释与编译
解释意味着页面是XML(文件扩展名.xml,内容类型text / xml或application / xml),并且处理指令所引用的XSLT样式表在浏览器中执行。
编译意味着在请求页面之前,浏览器会看到在您的开发环境或服务器上从XML转换而来HTML(文件扩展名.html,内容类型text / html)。 Xalan和Saxon是众所周知的XSLT处理器。
解释是未来。 所有现代浏览器都支持XSLT,并且有一些优点:
- 测试时,您将立即获得结果。 只需在您测试的每个浏览器中按F5即可反映源页面,CSS和XSLT样式表的更改。
- 减少了要传输到客户端的信息量。
- 客户会看到一个干净整洁的网页,因为尚未生成扩充功能。
但还要考虑缺点:
- 可能有些旧的浏览器不支持XSLT。 如果您为受控环境(内部网)发布页面,则不会有问题。
- 一些现代的浏览器禁止XSLT样式表引用另一个目录中的另一个样式表。
- 将XSLT与其他功能(例如SVG或iframe)结合使用,可能会导致某些浏览器出现问题。
- 因为大多数浏览器不支持XSLT 2.0或即将推出的3.0,所以您不能使用新功能。 没有XPath 2.0
if () then … else
,也没有用户编写的XPath函数。
无论是编译还是解释,在两种情况下,页面的其他转换(CSS,JavaScript)都在XSLT转换之后执行。
结论
在本文中,您学习了如何使用XSLT样式表来丰富XHTML文档。 您可以将本文中的示例用作构建您自己的XSLT样式表的起点。
翻译自: https://www.ibm.com/developerworks/web/library/wa-xsltstyle/index.html
xslt元素的使用