一、XSL(eXtensible Stylesheet Language)扩展样式表语言:主要包含三个部分——XSLT用于XML文档转换,XPath用于在XML文档中导航,XSL-FO用于XML文档格式化。
注意:XSL样式表本身也是一个XML文档,所以第一行必须为XML声明。
二、XSLT = XSLTransformations XSL转换,可将一种XML文档转换为另一种XML文档,或者说XSLT将XML源树转换为XML结果树,通过使用XPath来定义源文档中可匹配一个或多个预定义模板部分,一旦匹配被找到,XSLT就会调用模板将源文档中的匹配部分转换为结果文档。
三、XSLT是一种闭包,它的输入和输出都是树,可以管道化利用,如:文档1 -> 文档2-> 文档3。
四、XSLT语法:XSL样式表由一个或多个模板(template)的规则组成,每个模板含有当前某个指定节点被匹配时所应用的规则。
a) <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">元素
XSLT的根元素,用于定义该文档是一个XSLT样式表,上例中包含版本号以及XSLT命名空间两个属性。其中stylesheet也可写为transform,两者是完全相同的。
b) <xsl:import href="sourcePath"/>和<xsl:import href="sourcePath"/>
在根元素下,第一个<xsl:template>之前植入,用于直接引用外部的其他xsl。
区别在于当定义的规则和正文中的规则冲突时,import的规则优先级较低,include的规则优先级与正文的规则相同。
如:原book.xsl中有
<xsl:template match="title"> Title </xsl:template>
而另一个anotherBook.xsl中有include该文件,则NewTitle是无效的,依旧使用原模板中的Title。如果采用import,则可以覆盖原有book.xsl中的模板。
<xsl:include href="book.xsl"> (:<xsl:import href="book.xsl">:) <xsl:template match="title"> NewTitle </xsl:template>
c) <xsl:template math=”…”>元素
每个xsl样式表中至少包含一个,用于构造模板,match属性的值是XPath表达式,用于为整个模板定义文档,其中采用”/” 表示定义整个文档。可选用属性name,该属性将在后面用于模板重用。
d) <xsl:apply-templates select="expression" mode="name">元素
把一个模板应用于当前元素或其子元素。
通过select属性可以筛选匹配的元素或其子元素,*表示要选取整个节点集,省略该属性时选取当前结点的所有子节点。缺省情况下相当于select="text()",即选取文本。
通过mode属性用来区分相同元素的不同处理方法。
其中<xsl:apply-templates/>是默认执行该模板,当在和叶子节点相关联的模板中,可以不必写明。
如:用对cd下的title和artist分别应用模板,模板cd、title和artist中省略了<xsl:apply-templates/>。
<xsl:template match="cd"> <p> <xsl:apply-templates select="title"/> <xsl:apply-templates select="artist"/> </p> </xsl:template> <xsl:template match="title"> Title: <span style="color:#ff0000"> <xsl:value-of select="."/></span> <br /> </xsl:template> <xsl:template match="artist"> Artist: <span style="color:#00ff00"> <xsl:value-of select="."/></span> <br /> </xsl:template>
e) <xsl:value-of>元素
用于提取某个选定节点的内容,可以是文本、元素或者属性,并把值添加到转换的输出流中。可拥有属性select,该属性的值为一个XPath表达式。
如:下面的xsl语句选出了catalog/cd/title和catalog/cd/artist的值。
<td><xsl:value-of select="catalog/cd/title"/></td> <td><xsl:value-of select="catalog/cd/artist"/></td>
f) <xsl:for-each>元素
用于选取指定节点集中的每个元素。与value-of类似,它也有select属性,其值也是一个XPath表达式,当然在表达式中添加谓词作为判别式也可以用来筛选元素。
如:下面的xsl语句选出了artist为Bob Dylan的cd信息。
<xsl:for-each select="catalog/cd[artist=‘Bob Dylan‘]">
合法的比较运算符:= (等于),!= (不等于),< (小于),> (大于)
g) <xsl:sort>元素
用于对结果进行排序,紧跟<xsl:apply-templates>或<xsl:for-each>,是它们内部的一个元素,而不是属性。
sort可以拥有以下属性:
i. select="XPath",规定节点的排序关键字,即根据哪个节点/节点集排序。
ii. lang="language",规定排序所采用的语言。
iii. data-type = { "text" | "number" | QName },规定排序所采用的数据类型,默认为text。text是按所选节点的文本类型排序,即字典序;number则是按照所选节点的数据类型排序,如30,6,132按照text得到132,30,6,按照number得到6,30,132。
iv. order={"ascending"|"descending"},规定排序的顺序,默认为"ascending"。
v. case-order={"upper-first"|"lower-first"},规定是否首先按照大写/小写字母排序,比如选用了lower-first,则对于book,Book,CZ,cz排序结果为book,Book,cz,CZ。
如:根据artist的值排序。
<xsl:for-each select="catalog/cd"> <xsl:sort select="artist"/> <tr> <td><xsl:value-of select="title"/></td> <td><xsl:value-of select="artist"/></td> </tr> </xsl:for-each>
h) <xsl:if>元素
在<xsl:for-each>内部,它包含了一个“模板”,用于对XML文档内容的条件测试,只有在指定的条件成立时才会应用模板。
有且只有一个属性test,该属性的值为一个表达式,规定了要测试的条件。
如:找出售价大于10元的cd的名称和作者。
<xsl:for-each select="catalog/cd"> <xsl:if test="price > 10"> <tr> <td><xsl:value-of select="title"/></td> <td><xsl:value-of select="artist"/></td> </tr> </xsl:if> </xsl:for-each>
以下xsl语句显示的效果是最后一张cd的title输出后面跟!,倒数第二张和最后一张cd的title之间用“,and”连接,其余用逗号连接。
注意:xsl语句的每个if语句都会被测试!
<xsl:for-each select="catalog/cd"> <xsl:value-of select="title"/> <xsl:if test="position()!=last()"> <xsl:text>, </xsl:text> </xsl:if> <xsl:if test="position()=last()-1"> <xsl:text> and </xsl:text> </xsl:if> <xsl:if test="position()=last()"> <xsl:text>!</xsl:text> </xsl:if> </xsl:for-each>
i) <xsl:choose>元素
与<xsl:when>和<xsl:otherwise>结合,进行多重测试。只有when元素有且只有一个test属性。
基本语法:
<xsl:choose> <xsl:when test="expression"> ... Output ... </xsl:when> <xsl:when test="expression"> ... Output ... </xsl:when> <xsl:otherwise> ... Output ... </xsl:otherwise> </xsl:choose>
注意:when不会像if一样对一个测试点进行多次测试,好比switch-case语句加上break。
如:一个名为color的变量,如果当前测试的元素有color属性,则将color变量的值赋给当前测试元素的color属性;否则,将color属性置为green。
<xsl:variable name="color"> <xsl:choose> <xsl:when test="@color"> <xsl:value-of select="@color"/> </xsl:when> <xsl:otherwise>green</xsl:otherwise> </xsl:choose> </xsl:variable>
j) <xsl:call-template>元素:
<xsl:call-template name="templateName">用于实现模板重用。
k) <xsl:number/>元素:
用于测定当前节点在源文档中的位置,也可用于将格式化的数字插入结果树。
i. count=”xPathExpression”:可选属性,指定要计算的节点。
ii. level:可选属性,控制如何分配序号。
1. single——默认,即每个序号只与所在层序号有关;
2. multiple——每个序号包含层级关系;
3. any——所有层共用一个序号关系。
iii. format:格式标记,可为1数字计数,01与1唯一的区别在于01~09,a表示小写字母计数,A表示大写字母计数,i表示小写罗马数字计数,I表示大写罗马数字计数。
iv. value:自己提供数字代替产生的序号;
grouping-separator:规定采用什么符号来分割数字或组,默认为“,”;
grouping-size:规定分组的大小,默认为3。
如:
<xsl:number value="123456" grouping-separator="." grouping-size="2"/>
输出为12.34.56
<xsl:number value="12" grouping-size="1" grouping-separator="#" format="I"/>
输出为X#I#I,首先将12转换成大写罗马数字XII,然后对其进行分割。
如源books.xml为:
<?xml version="1.0" encoding="UTF-8"?> <list> <book ID="666"> <chapter>First Chapter</chapter> <chapter>Second Chapter <chapter>Subchapter 1</chapter> <chapter>Subchapter 2</chapter> </chapter> <chapter>Third Chapter <chapter>Subchapter A</chapter> <chapter>Subchapter B <chapter> subsub a</chapter> <chapter> subsub b</chapter> </chapter> </chapter> </book> </list>
目标输出为:
转换的xsl为:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions"> <xsl:template match="/"> <xsl:for-each select="//chapter"> <br/> <xsl:number level="multiple" format="1.A.a "/> <xsl:value-of select="./text()"/> </xsl:for-each> </xsl:template> </xsl:stylesheet>
如果将level选为single,则输出结果如下:
1 First Chapter
2 Second Chapter
1 Subchapter 1
2 Subchapter 2
3 Third Chapter
1 Subchapter A
2 Subchapter B
1 subsub a
2 subsub b
如果将level选为any,则输出结果如下:
1 First Chapter
2 Second Chapter
3 Subchapter 1
4 Subchapter 2
5 Third Chapter
6 Subchapter A
7 Subchapter B
8 subsub a
9 subsub b
l) <applet>属性值模板:
如:
<applet> <code class="Applet"/> <codebase>/src/code</codebase> </applet> <xsl:template match="/"> <xsl:apply-templates select="applet"> <applet code="{code/@class}" codebase="{codebase}/java"/> </xsl:apply-templates> </xsl:stylesheet>
实际效果为:
<applet code="Applet" codebase="src/code/java"/>
五、 XML与XSL关联:
<?xml-stylesheet type="text/xsl" href="***.xslt"?>
六、 XSL参数:<xsl:with-param name="…">
定义了传递给模板的参数的值,with-param的name属性的值必须与所调用的模板的param的name属性值相匹配,否则将被忽略。call-template和apply-templates中允许使用with-param元素。可以通过元素的内容设置参数值(如例子中),也可以通过select属性赋值。
如:
输入repeatTest.xml:
<?xml version="1.0" encoding="UTF-8"?> <Name> <AAA repeat="3"/> <BBB repeat="2"/> <CCC repeat="5"/> </Name>
转换repeatTest.xml:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions"> <xsl:template match="/Name/*"> <p> <xsl:call-template name="while"> <xsl:with-param name="test"> <xsl:value-of select="@repeat"/> </xsl:with-param> </xsl:call-template> </p> </xsl:template> <xsl:template name="while"> <xsl:param name="test"/> #test记录了repeat的次数 <xsl:value-of select="name()"/> #输出AAA或BBB或CCC <xsl:text/> <xsl:if test="$test!=1"> #判断当前repeat属性是否为1 <xsl:call-template name="while"> <xsl:with-param name="test"> <xsl:value-of select="$test - 1"/> #递归调用while模板,参数修正为test值减1,注意$test和-、-和1之间均有空格 </xsl:with-param> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet>
输出结果:
AAAAAAAAA
BBBBBB
CCCCCCCCCCCCCCC
七、 XSL变量:<xsl:variable name="…">
用于声明局部变量/全局变量,如果被声明为顶层元素则是全局的,如果在模板内部声明则为局部的。一旦设置了变量的值,就无法改变或修改该值,但可以通过其内容或select属性向变量添加值。注意:如果设置了select属性则variable不能包含任何内容了。
如:仍对上面的books.xml进行取每一层的最后一个chapter操作:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions"> <xsl:variable name="totalChapters"> <xsl:value-of select="//chapter[last()]"/> </xsl:variable> <xsl:template match="/"> <xsl:value-of select="$totalChapters"/> </xsl:template> </xsl:stylesheet>
操作结果:注意Third Chapter被应用了此模板,因此递归调用。
Subchapter 2
Third Chapter
Subchapter A
Subchapter B
subsub a
subsub b
Subchapter B
subsub a
subsub b
subsub b
八、 XSL中的key元素<xsl:key name="name" match="pattern" use="expression">
该元素是顶层元素,可以为指定的元素分配名称和值对,通过key()函数在样式表中使用。但此处的key不必是唯一的。
三个属性均为必需的,name规定键的名称,match规定键被应用到哪个节点,use指定要作为该键的值使用的表达式。
如定义一个键来寻找作者含有Jim Blue的书的所有作者:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions"> <xsl:key name="findAuthor" match="list/book" use="author"/> <xsl:param name="author">Jim Blue</xsl:param> <xsl:template match="/"> <xsl:copy-of select="key('findAuthor', $author)"/> </xsl:template> </xsl:stylesheet>
源keyTest.xml:
<?xml version="1.0" encoding="UTF-8"?> <list> <book ID="234"> <author>Jim Blue</author> <author>Dan Farm</author> <author>Blue Flowers</author> </book> <book ID="666"> <author>Mark Simp</author> <author>Jim Blue</author> <author>Green Trees</author> </book> <book ID="898"> <author>Jay Bart</author> <author>Red Tulips</author> </book> </list>
输出结果:
Jim Blue
Dan Farm
Blue Flowers
Mark Simp
Jim Blue
Green Trees
九、通过XSLT与XQuery生成HTML
给定students.xml文件,按照出生年月日排序,学号为Z00123101的学生信息用绿色显示,学号为Z00123102的学生信息用蓝色显示,其余用红色显示。
如
源students.xml文件:
<?xml version="1.0" encoding="UTF-8"?> <students> <student id="Z00123101"> <name>The No.1 student</name> <birthday>1987.2</birthday> <phone>62220001</phone> </student> <student id="Z00123102"> <name>the No.2 student</name> <birthday>1975.6</birthday> <phone>62220002</phone> </student> <student id="Z00123103"> <name>the No.3 student</name> <birthday>1978.8</birthday> <phone>62220003</phone> </student> <student id="Z00123104"> <name>the No.4 student</name> <birthday>1976.2</birthday> <phone>62220004</phone> </student> </students>
通过XSLT生成:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:template match="/"> <html> <head> <table border="1" cols="4" width="100%"> <tr> <th>No</th> <th>Name</th> <th>Phone</th> <th>Birthday</th> </tr> <xsl:for-each select="students/student"> <xsl:sort select="birthday"/> <xsl:choose> <xsl:when test="@id='Z00123101'"> <tr style="color:green"> <td><xsl:value-of select="@id"/></td> <xsl:apply-templates select="name|phone"/> <xsl:apply-templates select="birthday"/> </tr> </xsl:when> <xsl:when test="@id='Z00123102'"> <tr style="color:blue"> <td><xsl:value-of select="@id"/></td> <xsl:apply-templates select="name|phone"/> <xsl:apply-templates select="birthday"/> </tr> </xsl:when> <xsl:otherwise> <tr style="color:red"> <td><xsl:value-of select="@id"/></td> <xsl:apply-templates select="name|phone"/> <xsl:apply-templates select="birthday"/> </tr> </xsl:otherwise> </xsl:choose> </xsl:for-each> </table> </head> <body></body> </html> </xsl:template> <xsl:template match="name|phone|birthday"> <td><xsl:value-of select="."></xsl:value-of></td> </xsl:template> </xsl:stylesheet>
通过XQuery生成:
xquery version "1.0"; <html> <head> <table border="1" cols="4" width="100%"> <tr> <th>No</th> <th>Name</th> <th>Phone</th> <th>Birthday</th> </tr> { for $x in doc("students.xml")/students/student order by $x/birthday return if(data($x/@id)="Z00123102") then <tr style="color:blue"> <td>{data($x/@id)}</td> <td>{data($x/name)}</td> <td>{data($x/phone)}</td> <td>{data($x/birthday)}</td> </tr> else if(data($x/@id)="Z00123101") then <tr style="color:green"> <td>{data($x/@id)}</td> <td>{data($x/name)}</td> <td>{data($x/phone)}</td> <td>{data($x/birthday)}</td> </tr> else <tr style="color:red"> <td>{data($x/@id)}</td> <td>{data($x/name)}</td> <td>{data($x/phone)}</td> <td>{data($x/birthday)}</td> </tr> } </table> </head> <body/> </html>