XSLT 指 XSL 转换(XSL Transformations),这是一篇XSLT的教程,
概述
XSLT 用于将一种 XML 文档转换为另外一种 XML 文档,或者可被浏览器识别的其他类型的文档,比如 HTML 和 XHTML。通常,XSLT 是通过把每个 XML 元素转换为 (X)HTML 元素来完成这项工作的。
把文档声明为 XSL 样式表的根元素是 <xsl:stylesheet>
或 <xsl:transform>
。这两个是同义的,均可使用。
正确的样式表声明如下:
1 2 3
| <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> </xsl:stylesheet>
|
1 2 3
| <?xml version="1.0" encoding="UTF-8"?> <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> </xsl:transform>
|
而在XML文档中引用XSLT需要在文件头加一行声明:<?xml-stylesheet type="text/xsl" href="XSLT路径"?>
。
基本语法
template
模板就类似于编程语言中的函数,我们可以直接在其中编写XSLT语法,也可以在其他地方调用它。写在模板中的内容会以样式表的形式被显示出来,其基本框架为<xsl:template match="xpath"></xsl:template>
match 属性中的值为一个xpath路径,用于在XML文档中匹配要被显示的节点。举个例子:
1 2 3 4 5 6 7 8 9 10
| <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/book"> <html> <body> <h2>My books</h2> </body> </html> </xsl:template> </xsl:stylesheet>
|
这个模板指向了book节点,但由于我们还没学习如何调用节点中的值,所以只简单地输出了一些HTML格式,在输出的格式中会以
1 2 3 4 5
| <html> <body> <h2>My books</h2> </body> </html>
|
的HTML样式输出。
调用模板
在创建模板的时候,可以为其添加一个name属性作为名字:<xsl:template match="xpath" name="name">
,然后在其他位置就可以用<xsl:call-template name="template-name">
对其进行调用了,类似于函数调用的过程。
其他属性
- mode :用于区分同名模板,进行进一步标识
- priority :表示模板的优先级。当没有priority属性时,将执行后声明 的模板;有priority属性时,将使用 priority 取值较大 的模板。
- as :表示该模板应该返回的数据类型。如
<xsl:template match="book" as="element()">
表示该模板将会返回一个XML元素作为结果。as是一个可选的参数,如果不指定该参数,则模块可以输出任意的文本内容。
apply-templates
<xsl:apply-templates select="xpath" mode="mode-name"/>
元素用来从当前节点开始对子结点中符合xpath表达式的节点中BFS向下遍历当前模板,其中mode属性可以用来区分不同元素。听起来可能很乱,没事,我也没觉得我能讲清楚。但是看完以下例子就能明白了:
以下例子都建立在如下XML文档中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?xml version="1.0" encoding="UTF-8"?> <books> <book> <title>Harry Potter</title> <price>20</price> </book> <book> <title>C++</title> <price>35</price> <author> <name>thq</name> <name>THU</name> </author> </book> </books>
|
对其调用如下XSLT:
1 2 3 4 5 6
| <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="books"> <h3><xsl:apply-templates/></h3> </xsl:template> </xsl:stylesheet>
|
输出结果为 Harry Potter20C++35thqTHU
,这是因为我们没有限定select属性的值,默认将所有子节点都加入h3标签当中了。
倘若对其调用这个XSLT:
1 2 3 4 5 6
| <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="books"> <h3><xsl:apply-templates select="book/title"/></h3> </xsl:template> </xsl:stylesheet>
|
应该容易猜到,输出结果为 Harry PotterC++
。
param
<xsl:param name="param-name"/>
元素可以用来声明模板中的形参,而 <xsl:with-param name="param-name" select="xpath"/>
元素可以在调用模板的时候将xpath所指向的元素作为模板参数传入。在如下XML文档中:
1 2 3 4 5 6 7
| <?xml version="1.0" encoding="UTF-8"?> <books> <book> <title>Harry Potter</title> <price>20</price> </book> </books>
|
调用如下XSLT样式:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="books"> <xsl:call-template name="temp"> <xsl:with-param name="title" select="book/price"/> </xsl:call-template> </xsl:template> <xsl:template name="temp"> <xsl:param name="title"/> <h3><xsl:value-of select="$title"/></h3> </xsl:template> </xsl:stylesheet>
|
最终输出结果为 <h3>20</h3>
。
output
在XSLT中如果要规定输出时的样式,可以通过一行 <xsl:output/>
声明来实现,其属性值有以下几种可选取值:
属性 |
值 |
描述 |
method |
xml html text name |
定义输出的格式。默认是 XML(但是如果根节点的第一个子节点是 <html> ,且在这之前没有文本节点,则默认是 HTML)。 |
version |
string |
设置输出格式的 W3C 版本号。(仅在 method=“html” or method=“xml” 时使用)。 |
encoding |
string |
设置输出中编码属性的值。 |
omit-xml-declaration |
yes no |
“yes” 规定在输出中省略 XML 声明(<?xml...?> )。默认是 “no”。 |
standalone |
yes no |
“yes” 规定 XSLT 处理器应输出独立文档声明。默认是 “no”。 |
doctype-public |
string |
规定 DTD 中要使用的公共标识符。即输出中 DOCTYPE 声明的 PUBLIC 属性的值。 |
doctype-system |
string |
规定 DTD 中要使用的系统标识符。即输出中 DOCTYPE 声明的 SYSTEM 属性的值。 |
cdata-section-elements |
namelist |
一个空格分隔的元素列表,这些元素的文本内容应作为 CDATA 部分来输出。 |
indent |
yes no |
“yes” 规定输出应根据其层次结构进行缩排。 |
media-type |
string |
定义输出的 MIME 类型(数据的媒体类型)。默认是 “text/xml”。 |
value-of
<xsl:value-of select="xpath"/>
元素用于提取某个 XML 元素的值,并把值添加到转换的输出流中。select属性中的xpath值即为从模板匹配的节点开始 匹配的节点,举个例子:对于XML文档
1 2 3
| <book> <title>Harry Potter</title> </book>
|
调用以下XLST模板:
1 2 3 4 5 6 7
| <xsl:template match="/book"> <html> <body> <h2><xsl:value-of select="title"/></h2> </body> </html> </xsl:template>
|
会得到一行以HTML的h2格式输出的Harry Potter 。
for-each
<xsl:for-each select="xpath">
的用处很显然了,就是选取匹配的节点组中的每个元素,比如对于XML文档
1 2 3 4 5 6 7 8 9 10 11
| <?xml version="1.0" encoding="UTF-8"?> <books> <book> <title>Harry Potter</title> <price>20</price> </book> <book> <title>TanHaoQiangC++</title> <price>35</price> </book> </books>
|
调用以下XSLT样式:
1 2 3 4 5 6 7 8
| <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/books"> <xsl:for-each select="book"> <h2><xsl:value-of select="title"/></h2> </xsl:for-each> </xsl:template> </xsl:stylesheet>
|
会分别 输出h2格式的Harry Potter与TanHaoQiangC++。
sort
可以在for-each中添加一行 <xsl:sort select="xpath"/>
元素来对xpath匹配到的节点进行排序。
if
<xsl:if test="expression">
的作用与编程语言中的if相同,用于筛选出符合expression表达式的项,对于上面那个XML文档的例子,如果调用以下XSLT样式:
1 2 3 4 5 6 7 8 9 10
| <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/books"> <xsl:for-each select="book"> <xsl:if test="price < 30"> <h2><xsl:value-of select="title"/></h2> </xsl:if>> </xsl:for-each> </xsl:template> </xsl:stylesheet>
|
则会筛选出price元素的值小于30的book,并输出其标题,即:Harry Potter。
choose
<xsl:choose>
元素用于结合 <xsl:when test="expression">
和 <xsl:otherwise>
来表达多重条件测试。类似于 if-else 语句的作用,不多赘述。
分别用来生成处理指令与注释。举个例子:
1 2 3 4 5 6
| <xsl:comment> <xsl:text>Processing instruction should appear next</xsl:text> </xsl:comment> <xsl:processing-instruction name="xml-stylesheet"> <xsl:text>type="text/xsl" href="some.xslt"</xsl:text> </xsl:processing-instruction>
|
1 2 3
| 输出
<?xml-stylesheet type="text/xsl" href="some.xslt"?>
|
variable
<xsl:variable name="var-name">
元素可以用来定义一个变量,在后续内容中可以重复调用:
1 2 3 4 5 6 7 8 9 10 11
| <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:variable name="var"> <table><tr>title</tr><tr>author</tr></table> </xsl:variable> <xsl:template match="book"> <html> <xsl:copy-of select="$var"/> </html> </xsl:template> </xsl:stylesheet>
|
其输出为
输出XML节点
如果要在XLST的输出中输出动态的XML节点(根据原XML文档内容动态变化),则不能用以上简单的方式输出,以下介绍几种动态生成XML节点的方式:
copy与copy-of
这两个元素的区别在于 <xsl:copy/>
元素可以输出当前节点的无子节点与属性版本,而 <xsl:copy-of select="xpath"/>
可以输出xpath所指向的节点的完整副本,下面举两个例子:对于该XML文档:
1 2 3 4 5 6 7
| <?xml version="1.0" encoding="UTF-8"?> <books> <book> <title>Harry Potter</title> <price>20</price> </book> </books>
|
调用copy节点的XSLT:
1 2 3 4 5 6 7
| <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="book"> <xsl:copy/> </xsl:template> </xsl:stylesheet>
|
输出为:
1 2
| <?xml version="1.0" encoding="UTF-8"?> <book/>
|
调用以下含有copy-of元素的XSLT:
1 2 3 4 5 6 7
| <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="book"> <xsl:copy-of select="."/> </xsl:template> </xsl:stylesheet>
|
输出结果为:
1 2 3 4 5
| <?xml version="1.0" encoding="UTF-8"?> <book> <title>Harry Potter</title> <price>20</price> </book>
|
element
copy与copy-of可以用来输出原文档中已有的XML节点,但无法生成新节点,若要实现后者,则需要使用 <xsl:element name="element-name"></xsl:element>
元素。没什么好说的,应该看了就知道怎么用吧!
attribute与attribute-set
顾名思义,这个是用来为元素添加属性的,具体用法为 <xsl:attribute name="attribute-name">attribute-value</xsl:attribute>
,就用上方那个XML原文档举个例子吧,比如用这个XSLT样式:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="book"> <xsl:element name="BOOKS"> <xsl:copy> <xsl:attribute name="price"> <xsl:value-of select="price"/> </xsl:attribute> </xsl:copy> </xsl:element> </xsl:template> </xsl:stylesheet>
|
其输出即为:
1 2 3 4
| <?xml version="1.0" encoding="UTF-8"?> <BOOKS> <book price="20"/> </BOOKS>
|
而 <xsl:attribute-set name="set-name">
则可以将多个属性值封装起来,提高其复用性,可以在要使用的地方通过 use-attribute-sets="set-name"
的属性进行调用。比如以下这个XSLT样式,可以实现与上方那个相同的效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="book"> <xsl:element name="BOOKS"> <xsl:copy use-attribute-sets="set"/> </xsl:element> </xsl:template> <xsl:attribute-set name="set"> <xsl:attribute name="price"> <xsl:value-of select="price"/> </xsl:attribute> </xsl:attribute-set> </xsl:stylesheet>
|
XSLT中的其他机制
模块化
<xsl:include href="URI">
与 <xsl:import href="URI"/>
元素都可以用来导入其他XSLT样式。其唯一的区别在于:import 导入的样式表的优先级低于 导出的样式表,也就意味着可以在当前样式表中重写元素。而include 导入的样式表拥有与包含的样式表(including style sheet)相同 的优先级。
多文档
使用 document('URI')
函数可以读取另一个XML文档中的节点到当前XML中使用,比如: <xsl:for-each select="document('books.xml')/books">
索引
使用 <xsl:key name="key-name" match="pattern" use="expression"/>
与 key('key-name', 'value')
函数可以实现索引。
其中 key 元素中的 match 属性定义该键被应用到哪个节点,而 use 属性指定要作为每个节点的键的值使用的表达式。
比如对于XML文档:
1 2 3 4 5
| <persons> <person name="Tarzan" id="050676"/> <person name="Donald" id="070754"/> <person name="Dolly" id="231256"/> </persons>
|
定义一个索引: <xsl:key name="preg" match="person" use="@id"/>
,如果要找到所有 id=“050676” 的 person ,可以使用 <xsl:for-each select="key('preg','050676')">
。
提示
<xsl:key>
是顶级元素。
不能使用参数或变量引用作为key匹配的一部分。
只有在调用key()时,XSLT处理器才会创建相应的索引。
一个节点上可以声明多个键。
结
学了一天终于学完了我困了886。