|
|
|
[XML初学进阶]XML(38)合并 网上资源
|
|
4.1 什么是样式单
在第一章中我们讲过,对于一批XML数据,应用处理程序要综合XML文档、文档类型说明(DTD/Schema)以及样式单三方面要素来处理和显示它。前面两章已经分别介绍了和XML文档以及DTD/Schema相关的语法知识,现在我们就来继续讲讲什么是样式单,它又是如何为XML效犬马之力的。
读完了前三章,细心的读者一定已经发现,在XML文档中只包含了数据信息,并没有涉及文档如何显示。不错,制定XML标准的目的是要使数据结构化,赋予其明确的语意,使之易于进行数据交换。XML早已不再把目光局限在文字图象的显示上,而是要建立它们之间的内在关系。可以说,XML文档本身是重内容而不重形式。
可是,“人靠衣裳马靠鞍”,XML再好,也需要装扮得衣冠楚楚才能尽现其无穷魅力。XML结构化地组织信息固然好,但如果不加修饰地把一大堆枯燥的数据摆在那里,也足以令人眼花头痛。“云想衣裳花想容”,XML也有爱美之心,它用样式单(Style Sheet)为针,专门描述显示方式的标记为线,为自己缝制了漂亮的衣裳,在浏览器中风度翩翩地展现在我们面前。
样式单(Style Sheet)是一种专门描述结构文档表现方式的文档,它既可以描述这些文档如何在屏幕上显示,也可以描述它们的打印效果,甚至声音效果。样式单一般不包含在XML文档内部,而以独立的文档方式存在。与HTML描述数据显示方式的传统方法相比,样式单有许多突出的优点:
表达效果丰富目前,样式单可以支持文字和图象的精确定位、三维层技术以及交互操作等,对于文档的表现力远远超过HTML中的标记。更重要的是,样式单的标准规范独立于其它结构文档的规范,当需要实现更丰富的表达效果时,仅需修改样式单规范即可,不会牵涉到原始的XML文档内容。
文档体积小在实际应用中,常常给相同名称标记下的内容定义相同的表现方式,使用传统的方法需要在每个标记中予以描述,造成大量的重复定义。而在样式单中,对于同一个标记只需进行一次描述就足够了,大大缩小需要传输的文件的体积,可提高传输速度,并节约带宽。
便于信息检索样式单可以实现非常复杂的显示效果,但由于样式描述与数据描述相分离,显示细节的描述并不影响文档中数据的内在结构。因此,网络搜索引擎对文档进行搜索时,不会被种种显示描述标记所迷惑。
可读性好样式单对各种标记的显示进行集中定义,且定义方式直观易读。这使得它易学易用,可读性、可维护性都比较好。同时XML文档也相对简洁、清晰,突出对内容本身的描述功能。
正是由于样式单的这种种优点,W3C大力提倡使用样式单描述结构文档的显示效果。与之相应,XML关于文档浏览的基本思想是将数据与数据的显示分别定义。这样一来,XML格式文档不会重蹈某些HTML文档结构混杂、内容繁乱的覆辙,XML的编写者也可以集中精力于数据本身,而不受显示方式的细枝末节的影响。不仅如此,样式单还带来另一个好处,即定义不同的样式表可以使相同的数据呈现出不同的显示外观,从而适合于不同应用,甚至能够在不同的显示设备上显示。这样,XML数据就可以得到最大程度上的重用性,满足不同的应用需求。
迄今为止,W3C已经给出了两种样式单语言的推荐标准,一种是层叠样式单CSS(Cascading Style Sheets),另一种是可扩展样式单语言XSL(eXtensible Stylesheet Language)。下面,我们就来分别讲述这两种样式单。
4.2.1 CSS的书写规范
层叠样式单CSS是一种样式描述规则,目前W3C有两个推荐标准,CSS1和CSS2。CSS1于1996年12月通过,CSS2则于1998年5月通过。CSS2是在CSS1的基础上制定的,基本上涵盖了CSS1,并在CSS1的基础上增加了媒体类型、特性选择符、声音样式等功能,并对CSS1原有的一些功能进行了扩充。
其实,CSS制定之初的服务对象并不是XML,它最初是针对HTML提出的样式单语言,不过现在也身兼数职,同样可以很好地应用于描述XML文档的表现。利用CSS,我们可以定义HTML或XML文档中元素的显示效果,包括元素的位置、颜色、背景、边空、字体、排版格式等等。在具体考察CSS在XML中的应用之前,让我们先来讲一些有关CSS放之四海而皆准的规则,也就是CSS的书写规范。
CSS的基本思想是为结构文档中的各个标记定义出相对应的一组显示样式。定义的基本格式为:
选择符 { 样式属性:取值;样式属性:取值;... }
下面我们给出一个HTML的例子,为读者增加一些感性认识:
<HTML><HEAD> <STYLE> H1{color:red; } .myclass{color:green} H2.myclass{color:blue} #myid{color:brown} </STYLE></HEAD>
<BODY> <H1>这是红色的一号标题。</H1> <P class="myclass">"myclass"类中的正文是绿色的。</P> <H2 class="myclass">但"myclass"类中的二号标题是蓝色的。</H2><P class="myclass" id="myid">以"myid"为标识的正文则是棕色的。</P></BODY></HTML>
它的浏览结果为:
这是红色的一号标题。
"myclass"类中的正文是绿色的。
但"myclass"类中的二号标题是蓝色的。
以"myid"为标识的正文则是棕色的。
CSS几经修订,现已包容了非常全面复杂的显示效果。单介绍CSS,就可专门出一本书。为了节省篇幅,突出重点,我们只大致介绍一些CSS的基本定义方法,如果读者需要更详细的信息,还请查相关的书籍和参考手册。
选择符
选择符是指被施加样式的元素,浏览器在文件中碰到这些元素时,就使用定义好的样式来显示它们。基本的选择符包括标记、类、标识、伪类等等。
标记(tag)选择符标记可以是HTML中的标记,也可以是XML中已定义的标记。具体的定义方式是:
标记名 { 样式属性:取值;样式属性:取值;... }
在本例中,为HTML中的标记<H1>定义了样式,将该标记下的文本用红色显示,因此,浏览结果中的第一行是红色的。
类(class)选择符无论是HTML还是XML文档,有些内容是可以分类处理的,相应地,对于某一类的内容可以定义不同的样式予以显示。例子中定义了一个类“myclass”,并为它定义了绿色显示的样式,所以属于该类的元素,即第二行文本,显示出来是绿色的。需要说明的是,定义样式时class可以与标记相关联,也就是说class的样式受到包含它的标记的制约。因此,在样式单的第三行为属于myclass类的标记<H2>定义了黄色显示的样式,相应地,第三行文本呈黄色。与标记相关的类选择符与不相关的类选择符的定义方法分别是:
标记名.类名 { 样式属性:取值;样式属性:取值;... }
和
.类名 { 样式属性:取值;样式属性:取值;... }
另外,在对XML文档中的类定义样式时,首先该class应该是在DTD中预先声明了的,否则会导致错误的发生。
标识(id)选择符在HTML/XML文档中,常常要唯一地标识一个元素,即赋予它一个id标识,以便在对整个文档进行处理时能够很快的找到这个元素。CSS也可以将标识id作为选择符进行样式设定,定义的方法与类大同小异,只要把符号“.”改成“#”就行了。方法是:
标记名#标识名 { 样式属性:取值;样式属性:取值;... }
和
#标识名 { 样式属性:取值;样式属性:取值;... }
一般情况下,为标识定义的样式是优先于为类定义的样式的,因此例子中第四行中的文本虽然属于类“myclass”,但显示效果为棕色。
伪类(pseudo-classe)选择符伪类选择符主要是指链接锚点的一些特性,在CSS中可以为链接锚点的不同状态赋予不同的属性。如:
示 例
效 果
A:link { color: blue }
没访问过的链接颜色显示为蓝色
A:visited { color: red }
访问过的链接颜色显示为红色
A:active { color: yellow }
激活的链接颜色显示为黄色
A:hover { color: green }
鼠标滑过链接时颜色显示为绿色
此外,可以将某个样式同时施加在多个选择符指定的不同元素上,只要将在大括号括起来的样式定义之前的各选择符之间用逗号分隔即可。如果选择符之间用空格分隔,则是用前面的父元素来约束后面的子元素。
选择符,选择符,... { 样式属性:取值;样式属性:取值;... }
和
选择符 选择符 ... { 样式属性:取值;样式属性:取值;... }
样式属性
样式属性就是指元素的哪些属性可以在样式单中给予改变,在CSS1和CSS2中有很多的篇幅讲样式属性。其中CSS1中包括字体属性(字形、大小、粗细、倾斜等)、颜色属性、背景属性、文本属性、边框属性(页边空、边框、内空等)、显示属性(独立块、内联、列表、表格、隐藏等)几大类。在CSS2中对显示属性的最大改进就是增加了表格的显示方式,此外还增加了一些与页面排版、跨媒体出版相关的内容。
属性值
在定义样式时,除需指出样式所施加的元素、元素的属性之外,还要给属性赋予一个新值。根据属性的不同,属性值的选取也有所不同,主要不外乎以下四种:
长度在样式中很多的属性都与长度有关,如宽高、字号、字距、行距、边空、线宽等等。需要注意的是:当长度作为一个尺寸的度量,其单位是非常重要的,否则,失之毫厘,谬以千里,显示结果可能就会出乎你的意料之外了。
URL有时需要给某些属性赋予URL值,如背景图象属性(background-image)。在进行URL赋值时,要将URL放在url()之中,也可以将其用单引号或者双引号括起来。
颜色在CSS中颜色是个很重要的属性,颜色值的赋值有四种形式:颜色名称、十六进制数、十进制数及百分比方式,其中前两种方式较为常用。例如对于红色来讲可以用下面几种方法定义:
p { color:red }
p { color:#ff0000 }
p { color:rgb(255,0,0) }
p { color:rgb(100%, 0%, 0%) }
关键字这里的关键字是指预先定义好的字符型属性值,对于不同的属性有不同关键字值。例如上面提到的颜色名称实际上就属于关键字,其它的又如用于线型的none、solid、dashed、double等等。
4.2.2 使用CSS显示XML文档
尽管CSS功能强大,涵盖面极广,但仍然有较强的规律可循,比较简单易学。一旦掌握了其精髓,就可以轻松地将其为我所用,即便在XML中也不例外。不过,当我们将CSS实际运用于XML文档中时,对应于文档本身所面向的应用不同,CSS的使用方法也有所不同。
事实表明,XML语言自它产生之日起,就蕴藏了强大的生命力。在XML标准发布之后的短短的两年内,XML的技术已经渗入到了Internet应用的各个角落,不同应用领域的XML标准或XML文档对表现力的要求各不相同。有些XML文档主要面向数据交换,其表现形式相对简单;有些文档是专门面向Web发布的,它的表现力相对就要强一些。因此,在XML文档中使用CSS的方式也有所不同。总结起来,常用以下两种方式: 引用式和嵌入式。
引用式
引用式是指XML文档本身不含有样式信息,通过引用外部CSS文档来定义文档的表现形式。大部分XML文档都采用这种方式,这也与XML语言内容与形式分开的原则相一致。具体实现的方法是,在XML文档的开头部分写一个关于样式单的声明语句,如下:
<?xml-stylesheet type="text/css" href="mystyle.css" ?>
这样一来,按照声明语句的指示,该文档在浏览器上的表现方式就由样式文件mystyle.css所决定。
现在,就让我们来看一个新例子。下面是一段XML文档,描述的是一个学生花名册,其中有两个学生的资料。
student.xml
<?xml version="1.0" encoding="gb2312" ?><?xml-stylesheet type="text/css" href="mystyle.css"?>
<roster> 学生花名册 <student> <name>李华</name> <origin>河北</origin> <age>15</age> <telephone>62875555</telephone> </student> <student> <name>张三</name> <origin>北京</origin> <age>14</age> <telephone>82873425</telephone> </student></roster>
现在,我们来为它量体制作一件衣服:
mystyle.css:
roster,student{ font-size:15pt; font-weight:bold; color:blue; display:block; margin-bottom:5pt;}
origin,age,telephone{ font-weight:bold; font-size:12pt; display:block; color:block; margin-left:20pt;}
name{ font-weight:bold; font-size:14pt; display:block; color:red; margin-top:5pt; margin-left:8pt;}
此时,文件student.xml在IE下的浏览效果为:
500)this.width=500'>
这个样式单的显示效果是将学生信息列表显示。同样,我们还可以将学生信息用表格的形式显示,相应的样式单为:
mystyle.css:
roster{ display:table; margin-top:12pt;}student{ display:table-row;}name,origin,age,telephone{ display:table-cell;}name{ color:red; font-weight:bold;}
遗憾的是,IE不支持CSS2中关于列表形式的定义,所以只有用浏览器NetScape的升级版本Mozilla才能看到效果:
500)this.width=500'>
由此可见,对于相同的数据资料,定义不同的CSS样式单,它们也就以截然不同的外观呈现在我们眼前。
其实,在第三章讲述命名空间时我们曾经给出了一个例子,它为同一批天气预报的数据准备了两个CSS样式单,然后利用HTML的JS脚本在两种显示方式下进行切换。
内嵌式
内嵌式是指将CSS样式直接嵌入到XML文档内部,为元素设置style属性,并在属性值中给出对其样式的定义。这种用法主要出现在一些特殊的XML文档中,一般来讲内嵌CSS样式的XML文档本身就是面向显示的,如SVG、SMIL等。我们将在“XML协议”一章中专门讲述。
4.3.1 XSL概述
在上一节中我们已经讲了两种样式单中的一种——层叠样式单CSS,本节要介绍的另一种是可扩展样式单语言 XSL(eXtensible Stylesheet Languge),它也是由W3C制定的。 XSL这个样式语言自提出以来争议颇多,前后经过了几番大的修改。XSL最近的一个草案于2000年3月提出,仍然有待进一步修改完善,因此还不能作为正式依据。
CSS是一种静态的样式描述格式,其本身不遵从XML的语法规范。而XSL不同,它是通过XML进行定义的,遵守XML的语法规则,是XML的一种具体应用。这也就是说,XSL本身就是一个XML文档,系统可以使用同一个XML解释器对XML文档及其相关的XSL文档进行解释处理。
XSL由两大部分组成:第一部分描述了如何将一个XML文档进行转换,转换为可浏览或可输出的格式;第二部分则定义了格式对象FO(fomatted object)。在输出时,首先根据XML文档构造源树,然后根据给定的XSL将这个源树转换为可以显示的结果树,这个过程称作树转换,最后再按照FO解释结果树,产生一个可以在屏幕上、纸上、语音设备或其它媒体中输出的结果,这个过程称作格式化。
到目前为止,W3C还未能出台一个得到多方认可的FO,但是描述树转换的这一部分协议却日趋成熟,已从XSL中分离出来,另取名为XSLT(XSL Transformations),其正式推荐标准于1999年11月16日问世,现在一般所说的XSL大都指的是XSLT。与XSLT一同推出的还有其配套标准XPath,这个标准用来描述如何识别、选择、匹配XML文档中的各个构成元件,包括元素、属性、文字内容等。
如前所述,XSLT主要的功能就是转换,它将一个没有形式表现的XML内容文档作为一个源树,将其转换为一个有样式信息的结果树。在XSLT文档中定义了与XML文档中各个逻辑成分相匹配的模板,以及匹配转换方式。值得一提的是,尽管制定XSLT规范的初衷只是利用它来进行XML文档与可格式化对象之间的转换,但它的巨大潜力却表现在它可以很好地描述XML文档向任何一个其它格式的文档作转换的方法,例如转换为另一个逻辑结构的XML文档、HTML文档、XHTML文档、VRML文档、SVG文档等等,不一而足。
使用XSL定义XML文档显示方式的基本思想是:通过定义转换模板,将XML源文档转换为带样式信息的可浏览文档。最终的可浏览文档可以是HTML格式、FO格式、或者其它面向显示方式描述的XML格式(如前面提到的SVG和SMIL),限于目前浏览器的支持能力,大多数情况下是转换为一个HTML文档进行显示。
在XML中声明XSL样式单的方法与声明CSS的方法大同小异:
<?xml-stylesheet type="text/xsl" href="mystyle.xsl"?>
至于具体的转换过程,既可以在服务器端进行,也可以在客户端进行。两者分别对应着不同的转换模式:
服务器端转换模式 在这种模式下,XML文件下载到浏览器前先转换成HTML,然后再将HTML文件送往客户端进行浏览。有两种方式:
动态方式;即当服务器接到转换请求时再进行实时转换,这种方式无疑对服务器要求较高。
批量方式;实现将XML用XSL转换好一批HTML文件,接到请求后调用转换好的HTML文件即可。
客户端转换模式 这种方式是将XML和XSL文件都传送到客户端,由浏览器实时转换。前提是浏览器必须支持XML+XSL。
下面我们将着重介绍一些XSLT对XML文档的显示转换功能,并将XPath作为XSLT的基础予以介绍。对于FO,因为它的发展道路是路漫漫其修远兮,所以只用较小的篇幅介绍一下,使读者对其有一个概括性的了解。
4.3.2 一个XSLT的简单例子
为了让读者能够对XSLT有一个感性认识,很快地掌握它的精髓,我们先来看一个XSLT的简单例子。通过剖析这个例子,读者可以掌握一些XSLT的基本语法和功能,甚至可以照葫芦画瓢写出自己的XSLT文档。
我们仍然使用前面在讲述CSS时用过的“学生花名册”的例子。在这里,为了使用XSL样式单,样式单声明语句应改为:
<?xml-stylesheet type="text/xsl" href="mystyle.xsl"?>
mystyle.xsl文档如下:
<?xml version="1.0" encoding="gb2312" ?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/REC-html40">
<xsl:template> <xsl:apply-templates/> </xsl:template> <xsl:template match="/"> <HTML> <HEAD> <TITLE>学生花名册</TITLE> <STYLE> .title{font-size:15pt; font-weight:bold; color:blue } .name{color:red} </STYLE> </HEAD> <BODY> <P class="title" >学生花名册</P> <xsl:apply-templates select="roster"/> </BODY> </HTML> </xsl:template> <xsl:template match="roster"> <TABLE BORDER="1"> <THEAD> <TD> <B>姓名</B> </TD> <TD> <B>籍贯</B> </TD> <TD> <B>年龄</B> </TD> <TD> <B>电话</B> </TD> </THEAD> <xsl:for-each select="student" order-by="name"> <TR> <TD><B><xsl:value-of select="name"/></B></TD> <TD><xsl:value-of select="origin"/></TD> <TD><xsl:value-of select="age"/></TD> <TD><xsl:value-of select = "telephone"/></TD> </TR> </xsl:for-each> </TABLE> </xsl:template> </xsl:stylesheet>
将上例的XML文档用XSL样式转换为HTML文档的步骤是:先用XML解释器将XML文档解释成DOM对象,相当于建立了原文档的一个节点树。然后用XML解释器解释XSL文档,用模板匹配的方法去遍历XML节点树,将树中的节点按模板的设定转换为模板指示的显示语言,即HTML语言。 为看懂上例中的XSL源码,首先介绍一下XSL的几条主要语句:
主要语句
含 义
xsl:stylesheet
声明语句
xsl:template
相当于编程中函数的概念
xsl:template match = ""
相当于函数调用,去匹配引号中指定的节点
xsl:apply-templates
应用模板函数
xsl:apply-templates select =""
应用模板函数的调用,跳转到引号中指定的模板
xsl:for-each select = ""
循环语句,遍历与引号中的属性值相同的节点
xsl:value-of select = ""
赋值语句,取出引号中指定的属性值
知道了上面这些语句的含义,我们就可以分析一下这段XSLT源代码的执行过程了:
在作过XML声明和XSL声明之后,样式单利用<xsl:template> <xsl:apply-templates/> </xsl:template>声明XSL模板,并调用该模板。
根据<xsl:apply-templates/>,系统最先匹配XML源树的根节点。根节点用"/"表示,它的匹配方法在一对<xsl:template match="/">括起的源码中声明。按照这段代码,首先生成带有样式信息的HTML文档的开头一段代码:
<HTML> <HEAD> <TITLE>学生花名册</TITLE> <STYLE> .title{font-size:15pt; font-weight:bold; color:blue } .name{color:red} </STYLE> </HEAD> <BODY> <P class="title" >学生花名册</P>
下面,系统看到了<xsl:apply-templates select="roster"/>的指示,于是,它在XML源树中寻找标记为“roster”的节点进行匹配。就象函数调用一样,现在系统跳到了用<xsl:template match="roster">括起的“函数”中继续生成下面的HTML代码:
<TABLE BORDER="1"> <THEAD> <TD> <B>姓名</B> </TD> <TD> <B>籍贯</B> </TD> <TD> <B>年龄</B> </TD> <TD> <B>电话</B> </TD> </THEAD>
现在,系统又接到了新的指示 <xsl:for-each select="student" order-by="name">。这条指示要求系统寻找标记为“student”的子节点,并按照“name”下的内容将这些节点排序,然后一一处理。
对于每一个“student”子树中的内容,系统为其生成表中一行的内容。每一行包含四列,分别把标记为“name”、“origin”、“age”、“telephone”的子节点的内容填进去。其中“name”下的内容还是粗体显示。对应到本例中的XML数据,生成的HTML代码为:
<TR> <TD><B>李华</B></TD> <TD>河北</TD> <TD>15</TD> <TD>62875555</TD> </TR>
<TR> <TD><B>张三</B></TD> <TD>北京</TD> <TD>14</TD> <TD>82873425</TD> </TR>
处理完<xsl:for-each select="student" order-by="name">中的内容,系统继续生成HTML代码:
</TABLE>
至此,系统已处理完<xsl:template match="roster">中的所有内容,可以“函数返回”了。
系统返回到<xsl:template match="/">括起的源码中,完成HTML最后两行代码的生成:
</BODY></HTML>
把上面的HTML代码串起来,就是生成的转换结果文件,它在IE5中的浏览效果为:
500)this.width=500'>
匹配的过程从下面的“节点与模版匹配示意图”看得更加清晰:
500)this.width=500'>
不知读者是否记得,在第一章中,我们也给出了一个关于XSL样式单的例子,生成了列表形式显示的“联系人列表”信息。现在大家就可以自己分析一下这个XSL文件所定义的模板和执行的过程了。
4.3.3 节点匹配路径XPath
从上面的例子可以看出,在利用XSL进行转换的过程中,匹配的概念非常重要。在模板声明语句xsl:template match = ""和模板应用语句xsl:apply-templates select = ""中,用引号括起来的部分必须能够精确地定位节点。具体的定位方法则在XPath中给出。
之所以要在XSL中引入XPath的概念,目的就是为了在匹配XML文档结构树时能够准确地找到某一个节点元素。可以把XPath比作文件管理路径:通过文件管理路径,可以按照一定的规则查找到所需要的文件;同样,依据XPath所制定的规则,也可以很方便地找到XML结构文档树中的任何一个节点,显然这对XSLT来说是一个最最基本的功能。
不过,由于XPath可应用于不止一个的标准,因此W3C将其独立出来作为XSLT的配套标准颁布,它是XSLT以及我们后面要讲到的XPointer的重要组成部分。
在介绍XPath的匹配规则之前,我们先来看一些有关XPath的基本概念。
首先要说的是XPath数据类型。XPath可分为四种数据类型:
节点集(node-set)节点集是通过路径匹配返回的符合条件的一组节点的集合。其它类型的数据不能转换为节点集。
布尔值(boolean)由函数或布尔表达式返回的条件匹配值,与一般语言中的布尔值相同,有true和false两个值。布尔值可以和数值类型、字符串类型相互转换。
字符串(string)字符串即包含一系列字符的集合,XPath中提供了一系列的字符串函数。字符串可与数值类型、布尔值类型的数据相互转换。
数值(number)在XPath中数值为浮点数,可以是双精度64位浮点数。另外包括一些数值的特殊描述,如非数值NaN(Not-a-Number)、正无穷大infinity、负无穷大-infinity、正负0等等。number的整数值可以通过函数取得,另外,数值也可以和布尔类型、字符串类型相互转换。
其中后三种数据类型与其它编程语言中相应的数据类型差不多,只是第一种数据类型是XML文档树的特有产物。
另外,由于XPath包含的是对文档结构树的一系列操作,因此搞清楚XPath节点类型也是很必要的。回忆一下第二章中讲到的XML文档的逻辑结构,一个XML文件可以包含元素、CDATA、注释、处理指令等逻辑要素,其中元素还可以包含属性,并可以利用属性来定义命名空间。相应地,在XPath中,将节点划分为七种节点类型:
根节点(Root Node)根节点是一棵树的最上层,根节点是唯一的。树上其它所有元素节点都是它的子节点或后代节点。对根节点的处理机制与其它节点相同。在XSLT中对树的匹配总是先从根节点开始。
元素节点(Element Nodes)元素节点对应于文档中的每一个元素,一个元素节点的子节点可以是元素节点、注释节点、处理指令节点和文本节点。可以为元素节点定义一个唯一的标识id。元素节点都可以有扩展名,它是由两部分组成的:一部分是命名空间URI,另一部分是本地的命名。
文本节点(Text Nodes)文本节点包含了一组字符数据,即CDATA中包含的字符。任何一个文本节点都不会有紧邻的兄弟文本节点,而且文本节点没有扩展名。
属性节点(Attribute Nodes)每一个元素节点有一个相关联的属性节点集合,元素是每个属性节点的父节点,但属性节点却不是其父元素的子节点。这就是说,通过查找元素的子节点可以匹配出元素的属性节点,但反过来不成立,只是单向的。再有,元素的属性节点没有共享性,也就是说不同的元素节点不共有同一个属性节点。对缺省属性的处理等同于定义了的属性。如果一个属性是在DTD声明的,但声明为#IMPLIED,而该属性没有在元素中定义,则该元素的属性节点集中不包含该属性。此外,与属性相对应的属性节点都没有命名空间的声明。命名空间属性对应着另一种类型的节点。
命名空间节点(Namespace Nodes)每一个元素节点都有一个相关的命名空间节点集。在XML文档中,命名空间是通过保留属性声明的,因此,在XPath中,该类节点与属性节点极为相似,它们与父元素之间的关系是单向的,并且不具有共享性。
处理指令节点(Processing Instruction Nodes)处理指令节点对应于XML文档中的每一条处理指令。它也有扩展名,扩展名的本地命名指向处理对象,而命名空间部分为空。
注释节点(Comment Nodes)注释节点对应于文档中的注释。
下面,我们来构造一棵XML文档树,作为后面举例的依托:
<A id="a1"> <B id="b1"> <C id="c1"> <B name="b"/> <D id="d1"/> <E id="e1"/> <E id="e2"/> </C> </B> <B id="b2"/> <C id="c2"> <B/> <D id="d2"/> <F/> </C> <E/></A>
现在,我们就来介绍一些XPath中节点匹配的基本方法。
路径匹配路径匹配与文件路径的表示相仿,比较好理解。有以下几个符号:
符 号
含 义
举 例
匹配结果
/
指示节点路径
/A/C/D
节点"A"的子节点"C"的子节点"D",即id值为d2的D节点
/
根节点
//
所有路径以"//"后指定的子路径结尾的元素
//E
所有E元素,结果是所有三个E元素
//C/E
所有父节点为C的E元素,结果是id值为e1和e2的两个E元素
*
路径的通配符
/A/B/C/*
A元素→B元素→C元素下的所有子元素,即name值为b的B元素、id值为d1的D元素和id值为e1和e2的两个E元素
/*/*/D
上面有两级节点的D元素,匹配结果是id值为d2的D元素
//*
所有的元素
|
逻辑或
//B | //C
所有B元素和C元素
位置匹配对于每一个元素,它的各个子元素是有序的。如:
举 例
含 义
匹配结果
/A/B/C[1]
A元素→B元素→C元素的第一个子元素
name值为b的B元素
/A/B/C[last()]
A元素→B元素→C元素的最后一个子元素
id值为e2的E元素
/A/B/C[position()>1]
A元素→B元素→C元素之下的位置号大于1的元素
id值为d1的D元素和两个具有id值的E元素
属性及属性灯ヅ?/strong>在XPath中可以利用属性及属性值来匹配元素,要注意的是,元素的属性名前要有"@"前缀。例如:
举 例
含 义
匹配结果
//B[@id]
所有具有属性id的B元素
id值为b1和b2的两个B元素
//B[@*]
所有具有属性的B元素
两个具有id属性的B元素和一个具有name属性B元素
//B[not(@*)]
所有不具有属性的B元素
A元素→C元素下的B元素
//B[@id="b1"]
id值为b1的B元素
A元素下的B元素
亲属关系匹配XML文档可归结为树型结构,因此任何一个节点都不是孤立的。通常我们把节点之间的归属关系归结为一种亲属关系,如父亲、孩子、祖先、后代、兄弟等等。在对元素进行匹配时,同样可以用到这些概念。例如:
举 例
含 义
匹配结果
//E/parent::*
所有E节点的父节点元素
id值为a1的A元素和id值为c1的C元素
//F/ancestor::*
所有F元素的祖先节点元素
id值为a1的A元素和id值为c2的C元素
/A/child::*
A的子元素
id值为b1、b2的B元素,id值为c2的C元素,以及没有任何属性的E元素
/A/descendant::*
A的所有后代元素
除A元素以外的所有其它元素
//F/self::*
所有F的自身元素
F元素本身
//F/ancestor-or-self::*
所有F元素及它的祖先节点元素
F元素、F元素的父节点C元素和A元素
/A/C/descendant-or-self::*
所有A元素→C元素及它们的后代元素
id值为c2的C元素、该元素的子元素B、D、F元素
/A/C/following-sibling::*
A元素→C元素的紧邻的后序所有兄弟节点元素
没有任何属性的E元素
/A/C/preceding-sibling::*
A元素→C元素的紧邻的前面所有兄弟节点元素
id值为b1和b2的两个B元素
/A/B/C/following::*
A元素→B元素→C元素的后序的所有元素
id为b2的B元素、无属性的C元素、无属性的B元素、id为d2的D元素、无属性的F元素、无属性的E元素。
/A/C/preceding::*
A元素→C元素的前面的所有元素
id为b2的B元素、id为e2的E元素、id为e1的E元素、id为d1的D元素、name为b的B元素、id为c1的C元素、id为b1的B元素
条件匹配条件匹配就是利用一些函数的运算结果的布尔值来匹配符合条件的节点。常用于条件匹配的函数有四大类:节点函数、字符串函数、数值函数、布尔函数。例如前面提到的last()、position()等等,这里我们就不再赘述。
以上这些匹配方法中,用得最多的还要数路径匹配。在前一节的例子中,无论是在语句<xsl:template match="roster">中,还是在语句<xsl:value-of select="name"/>中,都是依靠给出相对于当前路径的子路径来定位节点的。
4.3.4 XSLT句法与函数
从前面的例子中,相信读者已经大概了解了XSLT的一般形态及功能。在这一小节里,我们再来综合地论述一下。
文档结构
前面说过,XSLT文档本身是XML文档,因此文档的第一句自然是:
<?xml version="1.0" ?>
接下来是样式单部分:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">… …</xsl:stylesheet>
也可以写作:
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">… …</xsl:transform>
xsl:transform与xsl:stylesheet具有相同的含义,都表示元素所包含的内容为样式单。xsl:stylesheet元素必须包含有"version"属性,用以指示该XSL文档遵从哪一个版本的XSL标准。另外,xmlns:xsl指示了XSL的命名空间,在XSLT标准中,定义了XSLT的命名空间为http://www.w3.org/1999/XSL/Transform。
XSLT在进行转换时,首先遍历XML源文档树,找到要处理的节点,然后将定义好的模板信息施加到该节点中。
模板及应用
xsl:template是模板元素,通常每个xsl:template有一个节点匹配属性,由"match="指定。在对模板进行匹配时使用"xsl:apply-templates",选择要匹配的模板,相当于一个调用的过程。对节点的匹配规则遵照XPath。
不同的模板设计,可以导致同一个文档有不同的输出效果。xsl:template元素有一个mode属性,可以根据需要去匹配不同模式的模板。若将前例作如下修改:
<xsl:template match="/" mode="blue"> …<TITLE>学生花名册</TITLE> <STYLE> .title{font-size:15pt; font-weight:bold; color:blue }…
<xsl:template match="/" mode="red"> …<TITLE>学生花名册</TITLE> <STYLE> .title{font-size:15pt; font-weight:bold; color:red }…
如果要将TITLE输出为蓝色,则用下面语句匹配:
<xsl:apply-templates select="/" mode="blue"/>
如果要将title输出为红色,则写为:
<xsl:apply-templates select="/" mode="red"/>
此外,模板总是与节点相对应的,一个节点可能对应于不同的模板,那么如何确定各模板匹配的先后次序呢?XSLT中可为xsl:template设置优先级,写法是:
<xsl:template match="student" priority="n"> //n为优先级数
计算节点值
在使用XSLT进行转换时,常常需要获取节点值,使用xsl:value-of元素可达到这个目的,如下例:
<xsl:value-of select="origin"/>
得到的是学生原籍的值,select属性指定要获取的是哪一个节点的节点值。
循环处理
使用xsl:for-each可对所选节点依次进行处理,如例中在生成表格处理中,就是利用循环将各个学生的信息取出放入表格中的,写法是:
<xsl:for-each select="student" order-by="name"> …</xsl:for-each>
排序
对于用xsl:for-each或xsl:apply-templates匹配的节点,可使用xsl:sort将所选节点内容进行排序,如:
排序方式
举 例
含 义
按大小写排序
<xsl:sort case-order="upper-first" select="@id"/>
以id为关键字按大写优先排序
<xsl:sort case-order="lower-first" select="@id"/>
以id为关键字按小写优先排序
按字母顺序排序
<xsl:sort order="ascending" select="@id "/>
以id为关键字按字母升序排序
<xsl:sort order="descending" select="@id "/>
以id为关键字按字母降序排序
按数据类型排序
<xsl:sort data-type="text" select="@id"/>
以id为关键字按文本类型排序,如对于一组id数据101,2,44,305来说,排序结果是101,2,305,44
<xsl:sort data-type="number" select="@id"/>
以id为关键字按数据类型排序,上面一组数据的排序结果是2,44,101,305
另外,还有一种指定排序的方法,就是在前面学生花名册例中所使用的order-by:
<xsl:for-each select="student" order-by="name">
也可使得输出学生时按名字排序。
元素与属性创建
XSLT是一个动态的样式单,在处理过程中可产生新的元素或元素属性,方法如下:
内 容
元 素
举 例
转换结果
创建元素
xsl:element
<xsl:element name="TITLE">学生花名册</xsl:element>
<TITLE>学生花名册</TITLE>
创建属性
xsl: attribute
<TITLE><xsl:attribute name="style">color:blue </xsl:attribute>学生花名册</TITLE >
<TITLE style="color:blue">学生花名册</TITLE>
创建文本
xsl:text(可以保护文本中的空白字符)
<xsl:text> 这是学生花名册 </xsl:text >
输出文字:这是学生花名册
创建处理指令
xsl:processing-instruction
<xsl:processing-instruction name="xml-stylesheet">href="book.css"type="text/css"</xsl:processing-instruction>
<?xml-stylesheet href="book.css" type="text/css"?>
创建注释
xsl:comment
<xsl:comment>以下是学生花名册,请勿删改!</xsl:comment>
<!-- 以下是学生花名册,请勿删改!-->
节点拷贝
在对XML文档进行处理时,XSLT还可以通过拷贝的方式复制节点,方法是利用xsl:copy和xsl:copy-of。其中xsl:copy只拷贝当前节点,不包括子节点和属性;而xsl:copy-of的拷贝内容则包括当前节点、子节点和属性。例如对于:
<p id="p1">A <B>is a char</B> </p>
如果样式单写为如下形式:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="p"> <DIV> <xsl:text> copy-of : </xsl:text> <xsl:copy-of select="."/> </DIV> <DIV> <xsl:text> copy : </xsl:text> <xsl:copy/> </DIV> </xsl:template> </xsl:stylesheet>
转换后生成如下代码:
<DIV> copy-of : <p id="p1">A <B>is a char</B> </p></DIV><DIV> copy : <p/></DIV>
由此可见,两种拷贝方式结果大相径庭。
输出格式与编码问题
XSLT是一个转换语言,它的目的是将XML源文档转换为另一种格式文档,它的输出结果可以是HTML文档,也可以是带CSS的XML文档。具体的输出格式由xsl:output 指定。如果要输出为HTML文档,则写为:
<xsl:output method="html"/>
同样,要输出XML文档写为:
<xsl:output method="xml"/>
如果文档中不出现xsl:output,将缺省输出为XML文档,但如果在匹配模板时使用了<HTML>标记,则输出为HTML文档。输出为HTML文档时系统都会自动加上下面语句:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
此外,还可以利用xsl:output指定编码方式,如UTF-8,UTF-16,GB2312等。例如:
<xsl:output method="html" encoding="GB2312"/>
它指定了该XSLT的输出结果是HTML格式,编码方式为中文。
4.3.5 FO概览
FO(Formatting Object)又称为格式对象,本来是XSL标准中两大模块之一,但由于引来的争论颇多,成了XSL标准中的老大难问题,所以目前鲜有使用。现在XSL中实现转换功能的部分XSLT单独分离出来,独自成了推荐标准,剩下FO动向不明。既然如此,我们也就不费太多的篇幅在FO上,免得有朝一日FO被改得面目全非,读者还要费一番力气擦去这些得来的过时信息。
FO是直接面向内容的显示格式的。它定义了一个字典,或称之为符号集,字典中都是关于排版格式的一些关键字。再配上定义的XSL属性,便可表达出各种显示信息。
FO文档格式也是XML格式,遵从XML语法规范。它的命名空间是fo,声明如下:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
FO的基本单位是称之为area的矩形区,area内可以包含文本、图象或其它的格式对象。在XSL中定义了五十多个格式对象,并定义了更多的属性,对象加属性可以描述各种显示版面。从与area的关系上看,FO可以分为三类:
建立area的FO,这类FO可以新开辟一块area做文章
得到area的FO,这类FO只用来找到所需的area
包含在area之中的FO,主要用来描述显示方式,更贴近内容
从FO的功用来讲,又可以分为声明与版面描述FO、块级FO、内联级FO、表格FO、列表FO、链接与分枝FO、跨行FO、其它类FO。好了,现在我们已经把XSL的总体框架和具体语法规则介绍给大家。XSL的基本思想无外乎是树匹配,很象程序员所擅长的一层套一层的函数调用;但它描述显示方式的功能又十分强大,要想得心应手地驾驭这匹千里马,就需要诸位勤学多用了。
4.4 两种样式单的比较
本章的前几节花了很大的篇幅介绍了XML的样式单--CSS和XSL。CSS和XSL均属于样式单的一种,都可以用来设定文档的外观。那么,它们有什么区别呢?比较起来,它们主要有以下几个大的不同:
用途不同CSS最早是针对于HTML提出的,后来又将其应用于XML之中,它既可以为HTML文档中的各个成分设定样式,又可以为XML中的成分设定样式。XSL是专门针对XML提出的,它不能处理HTML文档。但它有一个CSS无法达到的功能,即用一个命令行将一个XML文档转换为另一个文档并存盘。
处理结果不同XSL采用的是一种转换的思想,它将一种不含显示信息的XML文档转换为另一种可以用某种浏览器浏览的文档,转换后的输出码或者存为一个新的文档,或者暂存于内存中,但都不修改源代码。而CSS则没有任何转换动作,只是针对结构文档中的各个成分,依照样式规定一一设定外观式样,再由浏览器依据这些式样显示文档,在整个过程中没有任何新码产生。
表现能力不同在XSL中定义的90%的样式规定,实际上在CSS中都有定义。但仍然有一些效果是CSS无法描述的,必须使用XSL不可。这些功能包括文本的置换,例如将一个美国的时间表示格式转换为一个中国的时间表示格式;根据文本内容决定显示方式,例如将60分以上的分数用黑色显示,60分以下的分数用红色显示;将文档中的成分按照某一个子成分的值进行排序,例如将商品按售价进行排序。此外,还有对于超链接的支持,对于FRAME的支持,对于某些语种文字从上到下,行从右到左的排列格式的支持等,都是XSL所独有的。
语法不同XSL是根据XML的语法进行定义的,实际上又是XML的一种应用。而CSS的语法自成体系,且比较简单,易学易用。
综上所述,一个XML文档的显示方式可以归纳为三种:即利用CSS显示,利用XSL转化为FO显示,以及利用XSL转化为HTML文档显示(这个HTML文档中可包含CSS样式)。
500)this.width=500'>
随着利用XML定义的各种面向显示方式描述的置标语言的不断成熟和浏览器显示效果的不断丰富,在不久的将来,我们就可以利用名空间,通过XSLT将一个XML数据文档转换为集各种描述显示方式的标记于大成的文档,使浏览器具有更强的表达力,为网络数据提供越来越生动逼真、活灵活现的展现方式。
500)this.width=500'>
| |
|
|
|
|
|
回复:XML(38)合并 网上资源 |
|
|
|
123(游客)发表评论于2008/5/23 15:52:58
|
» 1 »
|