面向服务的计算和web数据管理第4章 XML数据表示和处理_第1页
面向服务的计算和web数据管理第4章 XML数据表示和处理_第2页
面向服务的计算和web数据管理第4章 XML数据表示和处理_第3页
面向服务的计算和web数据管理第4章 XML数据表示和处理_第4页
面向服务的计算和web数据管理第4章 XML数据表示和处理_第5页
已阅读5页,还剩198页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

面向服务的计算和web数据管理第4章XML数据表示和处理在面向服务的计算和开发中,XML用来表示几乎所有的语言、协议以及数据结构,包括SOAP、WSDL、UDDI、ebXML、BEPL、OWL、服务调用的返回值等。甚至.Net使用的内部文件也是XML格式的,例如配置文件web.config,它用来存储应用的设置、用户数据、安全选项以及XHTML,XHTML用于访问ASPX页而产生的页。XHTML是基于XML标准的HTML的一个严格版本。ADO.Net数据库管理中的数据集也用XML表示数据表的集合,数据表是C#程序与数据库之间的数据单元。本章介绍XML语言以及相关技术,包括XML处理、文件类型定义、概要、确认、转换,如图4.1所示。后面的章节将讨论基于XML的数据库和查询语言XQL。书中其他部分也和XML及其应用密切相关,包括第5章的Web服务描述语言和组合语言,第7章的本体语言。

图4.1XML及其相关技术

XML(可扩展标记语言)是一种定义其他的Web服务标准、协议、接口、文档和数据的通用元语言。XML是能够自我描述的纯文本语言。它对句子、语句、段甚至整个文档使用基本的标签对。这些标签对为它们封装的数据提供附加信息。XML用元素和属性提供文档的逻辑结构和物理结构。XML包含元数据,即关于数据的数据。XML就是用来定义其他语言的一种元语言。4.1XML基础4.1.1XML和HTML

在讨论XML之前,让我们先看看HTML(超文本标记语言),一种编写Web页面的标准格式化语言。它用不同的标签对定义Web页中显示的文本和图的不同格式。例如:

<html>

<h3>IEEEInternationalWorkshoponObjectOrientedRealTimeDependableSystems,Sedona</h3>

<li>IEEEComputerSocietyPress,2005,<b>ISBN</b>0769523471</i><br>

<li>Objectorientedcomputing</li>

<li>Realtimecomputing</li>

<li>Dependablecomputing</li>

</html>

在Web页面中,这段HTML代码显示如下:

IEEEInternationalWorkshoponObjectOrientedRealTimeDependableSystems,Sedona

IEEEComputerSocietyPress,2005,ISBN0769523471

Objectorientedcomputing

Realtimecomputing

Dependablecomputing格式是由标签对控制的。<h3></h3>这对标签指定引用文本是三级头部格式。<li></li>这对标签指定引用文本是一个列表项。<b></b>这对标签指定引用文本是黑体的。<i></i>这对标签指定引用文本是斜体的。单独标签<br>是指开始新的一行。

如果我们用XML来描述同样的信息,它应该是这样的:

<?xmlversion="1.0">

<proceedings><title>IEEEInternationalWorkshoponObjectOrientedRealTimeDependableSystems</title>

<location>Sedona</location>

<publisher>IEEEComputerSocietyPress</publisher>

<year>2005</year>

<ISBN>0769523471</ISBN>

<keyword>Objectorientedcomputing</keyword>

<keyword>Realtimecomputing</keyword>

<keyword>Dependablecomputing</keyword>

</proceedings>HTML和XML代码之间的相似性是明显的:它们都用标签定义数据元素,它们都定义属性;都使用嵌套标签;两者都被设计为既供机器又供人阅读。两者的不同点不那么明显但是意义很大,如表4.1所示。表4.1HTML和XML语言之间的区别

4.1.2XML语法

一个XML文档的开始部分是由一个声明和可选的对外部文档的引用组成的序言。然后是根元素,它包含若干子元素。

<?xmlversion="1.0"encoding="UTF-8">

<instructorcourse="Service-OrientedComputing">

<name>

<first>John</first>

<last>Doe</last>

</name>

</instructor>文档的第一行声明这个文档用的是XML1.0版本和UTF-8编码方式。余下的行包含保存在XML文件中的数据,这些数据也称作“元素”。每个元素包含的内容放在一对标签(开始和结束标签)中。标签名不是预先定义的,除了一些约束外,可以自由选择。一个标签必须由一个字母、下划线或冒号开始。不能由保留字XML(不分大小写)开始。

用类似BNF语法,一个元素的定义如下:

Element∶∶=EmptyElement|<StartTag>Content<EndTag>

EmptyElement∶∶=<StartTag><EndTag>|<StartTag/>StartTag∶∶=TagName|TagNameAttributes

EndTag∶∶=/TagName

Attributes∶∶=Attribute|Attribute|Attributes

Attribute∶∶=name=′CDATAstring′|name="CDATAstring"

Elements∶∶=Element|ElementElements

Content∶∶=PCDATAstring|Elements

空元素<StartTag><EndTag>可以用<StartTag/>形式的单个标签表示。问题是,为什么需要空元素?原因是空元素也可以具有属性。例如:<photoimage=“myPhoto.jpeg”/>是<photoimage=“myPhoto.jpeg”></photo>的精简写法。

稍后解释定义中的CDATA和PCDATA。下面的例子是一个具有子元素和属性的XML文档。

<instructorcourse="Service-OrientedComputing"officeHours="4">

<title>Professor</title>

<name>

<first>John</first>

<last>Doe</last>

</name>

</instructor>

哪些信息应该作为子元素或属性存储是没有固定规则的。然而,一般情况下:

①元素通常定义那些构成文档必需的数据。②属性通常定义给出附加信息的带外数据。

编写XML文档必须遵循以下语法规则及约束:

①必须和/TR/RECxml中的XML规范一致。

②有一个唯一的根元素,其他的元素都是它的子元素或子孙元素。

③每个元素位于开始和结束标签之间。

④标记可以嵌套但不可以重叠。例如,下面这样是不被允许的:<title>Professor<name>Doe</title></name>

⑤标记应该是自描述的并且能说明嵌入其中的数据的真实意义。

⑥元素和标记的名称必须满足某些约束。

⑦属性值必须放在引号里面。单引号和双引号都是有效的,但双引号更常见。

⑧属性常常包含在元素的开始标记之内。

<courselevel=―Sophomore‖required=―true‖>

Service-OrientedComputing

</course>⑨元素允许有多个属性,但每个属性有唯一的名称,也就是同一个属性名在一个元素中只能出现一次。

⑩和元素相比,程序操作属性更难。

一个XML文档可表示成一棵有根树,如图4.2所示。椭圆节点是开始标记名称,平行四边形是属性,矩形是元素内容。

XML文档使用CDATA(字符数据)和PCDATA(已解析字符数据)这两种数据类型来处理保留字符的显示。5个字符作为标记被保留下来,解析器需要把它们从文本内容中区分出来。

图4.2用有根树表示XML文档字符实体名称含义

<lt小于

>gt大于

&符号

′apos撇号,例如computer′skeyboard

"quot引用

在XML中允许用不同的方法区分它们:

(1)对这些字符使用实体引用。例如,为了表示0<x<100,我们可以用:<Range>0<x<100</Range>

(2)对这些字符使用字符引用(ASCII码)。例如:

<Range><x<100</Range>

但是,如果过多的使用保留字,XML文档的读写将会变得困难。例如,如果我们想在XML文档里编写如下的代码块。

<myCode>

functionAND(a,b){

if(a=="true"&&b=="true")then{return"true"}

else

{return"false"}

}

</myCode>

如下所示的代码引用方式,使程序很难读懂。

<myCode>

functionAND(a,b){

if(a=="true"&&b=="true")then{return"true"}

else

{return"false"}

}

</myCode>

为了解决这一问题,可以采用其他方法。XML解析器区分两种类型的文本数据:

(1)CDATA——出现在这对专用标记“<![CDATA[”与“]]>”之间的数据(2)PCDATA——CDATA标记以外的任何数据

在有大量标记字符的文本中使用CDATA标签使文本的可读性更好:

<myCode>

<![CDATA[

functionAND(a,b){

if(a=="true"&&b=="true")then

{return"true"}

else

{return"false"}

}]]>

</myCode>

XML解析器忽略(不做语法检测)CDATA,但解析PCDATA——也就是把它看作标记语言。这隐含说明了“<![CDATA[”与“]]>”标签之间的数据不必与XML语法一致,而这对标记之外的部分,必须与XML语法保持一致。在XML文档中的空白分隔符可能有含义也可能没有含义。XML定义四个字符为空白分隔符。名称和统一字符编码值为:制表(#x9),换行(#xA),回车(#dX)以及空格

(#x20)。在XML定义或处理中,可以定义两个选项:默认和保留。在默认状态下,多个空白分隔符被压缩(常规化)。如果指定为保留,则附加的空格不能移除。

在XML文档中可以添加注释,在“<!”与“>”之间的任何文本将会被看作注释而不被解析。4.1.3XML名字空间

名字空间是限定(划分)元素和属性名称,识别资源名称,避免命名冲突的一种机制。我们可以使用名字空间前缀(C++中的作用域操作符)进行限定,如下面的例子所示:

<?xmlversion="1.0"?>

<cse:Courses

xmlns:cse="/WSRepository/xml/Course.xsd"

xmlns:asu="/WSRepository/xml/rooms.xsd">

<cse:Course><cse:Name>DistributedSoftwareDevelopment</cse:Name>

<cse:Code>CSE445</cse:Code>

<cse:Level>Senior</cse:Level>

<asu:Roomasu:Image="layout210.jpeg">BYAC210</asu:Room>

<cse:Cap>40</cse:Cap>

</cse:Course>

<cse:Course>

<cse:Name>IntroductiontoProgrammingLanguages</cse:Name><cse:Code>CSE240</cse:Code>

<cse:Level>Sophomore</cse:Level>

<asu:Roomasu:Image="layout110.jpeg">BYAC110</asu:Room>

<cse:Cap>82</cse:Cap>

</cse:Course>

</cse:Courses>

注意,元素的属性不会自动划归到名字空间。在下面的例子中,Image属性不属于名字空间。

<asu:RoomImage="layout110.jpeg"></asu:Room>

然而,你可以明确的用名字空间前缀把一个属性划归到名字空间

<asu:Roomasu:Image="layout110.jpeg"></asu:Room>

在XML模式一节将对名字空间进行深入讨论,在那里,名字空间可被定义为模式文件。

一旦理解了在XML文档中如何表示数据,就可以开始处理(读和写)XML文档。

主要有两种解析器从XML中提取数据。

(1) DOM:文档对象模型,由W3C定义,网址为/TR/DOMlevel2core。它将整个文档读入到内存中以进行随机访问。但问题是如果XML文档很大,它将会占用整个内存。MSXML是一个支持DOM以及SAX处理的免费软件包。4.2XML数据处理(2)SAX:用于XML的简单(流类型)的API,由Java社区定义(不是W3C),网址为,它是基于事件的API,以流形式读取文档。

(3)XPath:面向路径的数据提取。

XML解析器被集成到.Net中,.Net框架类库(FCL)定义了一个名字空间System.Xml,以及用于读写XML文档的各种类。XmlDocument类与MSXML相似,如果你想用基于流的方式(SAX),可以使用XmlTextReader或者模式敏感的XmlvalidatingReader。名为XmlTextWriter的辅助类允许你创建XML文档。本节余下的部分,我们将通过下面的例子来阐明怎样处理XML文件。这个文件存储的位置为:/WSRepository/xml/Courses.xml。

<!Filename:Courses.xml>

<?xmlversion="1.0"encoding="UTF-8"?>

<Courses>

<Course>

<NameShort="IntrotoPL">

IntroductiontoProgrammingLanguages

</Name><Code>CSE240</Code>

<Level>Sophomore</Level>

<Room>BYAC110</Room>

<Cap>82</Cap>

</Course>

<Course>

<NameShort="DistrSoftDev">

DistributedSoftwareDevelopment

</Name>

<Code>CSE445</Code><Level>Senior</Level>

<Room>BYAC210</Room>

<Cap>40</Cap>

</Course>

</Courses>

图4.3用有根树表示XML文档4.2.1DOM:文档对象模型

XmlDocument类及相关类提供一组方法来操作DOM里的XML文档。DOM把文档看作树的根节点,每个节点是一个XmlNode类的实例,它向外提供一些方法与属性,这些方法与属性用于对XML树的遍历、对节点内容的读写、对节点的删除添加等。在DOM的.Net实现中,XmlNode类是一个基类。

XmlDocument由XmlNode派生(继承),并添加了自己的方法和属性,这些方法和属性支持文档的装载和存储、新节点的创建及其他操作。下面的语句创建一个XmlDocument对象,并用XML文档Courses.xml初始化。

XmlDocumentxref=newXmlDocument();//createanobject

xref.Load("Courses.xml");//callLoadmethodtoinstantiatetheobject

Load方法解析“Courses.xml”文件并在内存中创建树表达式。如果文档不符合语法规范,则抛出XmlException异常,也就是说,读取XML文件的时候Load方法要进行确认。可以用URL给出XML文档。下面嵌于Web的代码创建一个XmlDocument对象,并用URL给出的Courses.xml进行初始化。

<%@Pagelanguage=C#debug="true"%>

<%@ImportNamespace="System.Xml"%>

<SCRIPTrunat="server">

voidPage_Load(ObjectSender,EventArgse)

{

XmlDocumentxref=newXmlDocument();

xref.Load("/WSRepository/xml/Courses.xml");Console.WriteLine(xref.FirstChild.Name);

}

</SCRIPT>

一旦一个XML文档以对象的形式读入到内存中,就可以用编程语言对其进行操作。下面的C#代码是一个操作XML树的例子,它递归地打印树的元素。

usingSystem;

usingSystem.Xml;

classXMLDocApp{publicstaticvoidMain(){

XmlDocumentxref=newXmlDocument();

xref.Load("Courses.xml");//oritsURL

preorderTraverse(xref.DocumentElement);

}

staticvoidpreorderTraverse(XmlNodenode){//recursivemethod

Console.WriteLine("Type={0}\tName={1}\tValue={2}",node.NodeType,node.Name,node.Value);

if(node.HasChildNodes){

XmlNodeListchildren=node.ChildNodes;

foreach(XmlNodechildinchildren)

preorderTraverse(child);//recursivecall

}

}

}代码以前序方式解析XML树,也就是,先打印根元素,然后依次打印孩子元素。打印输出的结果如下:

Type=ElementName=CoursesValue=

Type=ElementName=CourseValue=

Type=ElementName=NameValue=

Type=TextName=#textValue=IntroductiontoProgrammingLanguages

Type=ElementName=CodeValue=

Type=TextName=#textValue=CSE240

Type=ElementName=LevelValue=Type=TextName=#textValue=Sophomore

Type=ElementName=RoomValue=

Type=TextName=#textValue=BYAC110

Type=ElementName=CapValue=

Type=TextName=#textValue=82

Type=ElementName=CourseValue=

Type=ElementName=NameValue=

Type=TextName=#textValue=DistributedSoftwareDevelopment

Type=ElementName=CodeValue=Type=TextName=#textValue=CSE445

Type=ElementName=LevelValue=

Type=TextName=#textValue=Senior

Type=ElementName=RoomValue=

Type=TextName=#textValue=BYAC210

Type=ElementName=CapValue=

Type=TextName=#textValue=40从输出结果可以看到,库函数把元素内容看作文本节点,元素内容的值看作文本节点的值。在.Net框架类库(FCL)中有许多其他类和方法,可以在联机文档中找到。

以下伪码说明了遍历树时常用的三个顺序:前序遍历,中序遍历,后序遍历。

preorderTraverse(p)PreOrderTreeTraversingAlgorithms

ifp≠0thenprint(p>data);

foreachchildnode

preorderTraverse(p>nextChild);

inorderTraverse(p)//InOrderTreeTraversingforbinarytreeonly

ifp≠0then

inorderTraverse(p>left);

print(p>data);

inorderTraverse(p>right);postorderTraverse(p//PostOrderTreeTraversingAlgorithms

ifp≠0then

foreachchildnode

postorderTraverse(p>nextChild);print(p>data);4.2.2SAX:XML的简单API

DOM允许你将整个XML文档存储到内存中,并向后、向前及横向访问(读和修改)树中的元素。但是,如果你只是想读取XML中的内容而对结构不感兴趣,可以使用SAX模型,并使用.NetFCL中的XmlTextReader类。

像XmlDocument一样,XmlTextReader属于System.Xml名字空间,提供了一个对XML文档只向前读的API。它是基于流的,就像使用标准的文件操作读一个文本文件一样。XmlTextReader比XmlDocument更好地利用了内存,因为它不会将整个文件一次性读入到内存。在读取文档、搜索特定的元素、属性或者其他内容项时,XmlTextReader比XmlDocument更加简单容易。

SAX最基本的思想是从文件、URL或者其他数据源创建XmlTextReader对象。然后重复调用XmlTextReader.Read()方法直到发现所搜索的内容。Read()的每次调用都使假想的游标移动到文档的下一个节点(通常用前序遍历)。如果到达文件末尾(EOF),操作停止。

XmlTextReader的属性,例如NodeType、Name、Value和AttributeCount显示当前节点的信息,XmlTextReader的方法,例如GetAttribute、MoveToFirstAttribute和MoveToNextAttribute,允许用户访问当前节点的属性(如果有)。

下面的程序具有前面使用XMLDocument类的程序的全部功能。此外,这段程序会处理异常并打印嵌入在XML文件中的属性。

usingSystem;

usingSystem.Xml;

classXMLSAXApp{

publicstaticvoidMain(){

XmlTextReaderreader=null;

try{

reader=newXmlTextReader("/WSRepository/xml/Courses.xml");reader.WhitespaceHandling=WhitespaceHandling.None;

while(reader.Read()){

Console.WriteLine("Type={0}\tName={1}\tValue={2}",

reader.NodeType,reader.Name,reader.Value);

if(reader.AttributeCount>0){//printattributes

while(reader.MoveToNextAttribute())

Console.WriteLine("Type={0}\tName={1}\tValue={2}",reader.NodeType,reader.Name,reader.Value);

}

}

}

finally{

if(reader!=null)reader.Close();

}

}

}程序输出结果如下:

Type=XmlDeclarationName=xmlValue=version="1.0"encoding="utf8"

Type=AttributeName=versionValue=1.0

Type=AttributeName=encodingValue=utf8

Type=ElementName=CoursesValue=

Type=ElementName=CourseValue=

Type=ElementName=NameValue=

Type=AttributeName=ShortValue=IntrotoPLType=TextName=Value=IntroductiontoProgrammingLanguages

Type=EndElementName=NameValue=

Type=ElementName=CodeValue=

Type=TextName=Value=CSE240

Type=EndElementName=CodeValue=

Type=ElementName=LevelValue=

Type=TextName=Value=Sophomore

Type=EndElementName=LevelValue=

Type=ElementName=RoomValue=Type=TextName=Value=BYAC110

Type=EndElementName=RoomValue=

Type=ElementName=CapValue=

Type=TextName=Value=82

Type=EndElementName=CapValue=

Type=EndElementName=CourseValue=

Type=ElementName=CourseValue=

Type=ElementName=NameValue=

Type=AttributeName=ShortValue=DistrSoftDevType=TextName=Value=DistributedSoftwareDevelopment

Type=EndElementName=NameValue=

Type=ElementName=CodeValue=

Type=TextName=Value=CSE445

Type=EndElementName=CodeValue=

Type=ElementName=LevelValue=

Type=TextName=Value=Senior

Type=EndElementName=LevelValue=

Type=ElementName=RoomValue=Type=TextName=Value=BYAC210

Type=EndElementName=RoomValue=

Type=ElementName=CapValue=

Type=TextName=Value=40

Type=EndElementName=CapValue=

Type=EndElementName=CourseValue=

Type=EndElementName=CoursesValue=

Pressanykeytocontinue...4.2.3XML文本编写器

XmlDocument类常用来读取XML文档。一旦以树操作方式把文档读入到内存,它就可以修改这个XML文档。然而,不能用这个类创建一个新的XML文档。.Net框架类库包含一个编写器类XmlTextWriter,而这个编写器类包含许多写方法,用于创建元素、属性、注释等。以下这段C#代码显示了XmlTextWriter类的一些常用的写方法。

writer=newXmlTextWriter("Courses.xml",System.Text.Encoding.Unicode);writer.Formatting=Formatting.Indented;

writer.WriteStartDocument();

writer.WriteStartElement("Courses");

writer.WriteStartElement("Course");

writer.WriteElementString("Name","SOC");

writer.WriteElementString("Code","CSE445");

writer.WriteElementString("Level","Senior");

writer.WriteElementStriflg("Room","BYAC210");

writer.WriteAttributeString("Image","layout210.jpeg");

writer.WriteElementString("Cap‖,"40");

writer.WriteEndElement();writer.WriteEndElement();

writer.WriteEndDocument();

上面的代码将生成下面的XML文档。

<?xmlversion="l.0"encoding"utf-16"?>

<Courses>

<Course>

<Name>SOC</Name>

<Code>CSE445</Code>

<Level>Senior</Level><RoomImage="layout210.jpeg">BYAC210</Room>

<Cap>40</Cap>

</Course>

</Courses>4.2.4Java中的XML处理

C#及其应用主要由微软支持,而Java应用主要由社区支持,因此有许多不同的开发环境和软件包都可用于基于Java的XML处理。本节将对其中一些进行介绍。

①JAXP:用于XML处理的JavaAPI,提供了创建和使用标准的SAX、DOM、XSLTAPIs的通用接口。

②JAXB:用于XML绑定的Java体系结构,定义了创建XML形式的Java对象(marshalling:用于其他应用程序),以及从这种结构中创建Java对象(unmarshalling:把这些对象用于自己的程序中)的机制。③JDOM:JavaDOM,从XML文档创建对象树。

④JAXRPC:用于XML远程调用的API,提供了在外部注册中心发布可用服务,并且在注册中心查询服务的机制。

让我们更详细的讨论一下JAXP,它由下面的软件包组成:

①Javax.xml.parsers:为不同开发商的SAX和DOM解析器提供一个通用接口。

②org.w3c.dom:定义了文档类(一个DOM),以及DOM中所有组成部分的类。

③org.xml.sax:定义基础的SAXAPIs。

④Java.xml.transform:定义XSLTAPIs,能够把XML转换成其他格式,例如HTML格式。

在Javax.xml.parsers包(http://J/j2se/1.5.0/docs/api/)里,定义了一组类,包含:

①SAXParserFactory:定义一个工厂API,使应用进行配置并获取基于SAX的解析器解析XML文档。

②SAXParser:定义了封装XMLReader实现类的API。

③DocumentBuilderFactory:定义一个工厂API,使应用获得一个从XML文件生成DOM对象树的解析器。

④DocumentBuilder:定义了从XML文档获取DOM文档实例的API。这个软件包为XML文档的处理提供了四个主要类。它使用SAXParserFactory类创建一个有很多接口或解析方法但没有实现的实例(对象)。用事件驱动编程编写的SAXParser类封装了SAXReader类,SAXReader类执行与SAX事件处理的会话。每个事件处理实现SAXParserFactory对象中的一个接口。由于有一组DefaultHandlers用于ContentHandler、ErrorHandler、DTDHandler和EntityResolver的实现,因此,如果用户没有实现自己的处理,可以使用这些默认的处理。下面的代码演示了如何在Java程序中使用这些类和处理,图4.4对这段代码进行了说明。

图4.4用类和事件处理实现接口importJava.io.FileReader;

importorg.xml.sax.XMLReader;

importorg.xml.sax.InputSource;

importorg.xml.sax.helpers.XMLReaderFactory;

importorg.xml.sax.helpers.DefaultHandler;

publicclassMySAXAppextendsDefaultHandler{

publicMySAXApp(){super();}//constructor

publicstaticvoidmain(Stringargs[])throwsException{

XMLReaderxr=XMLReaderFactory.createXMLReader();MySAXApphandler=newMySAXApp();

xr.setContentHandler(handler);

xr.setErrorHandler(handler);

//Parseeachfileprovidedviathecommandlineinput

for(inti=0;i<args.length;i++){//getnumberoffilenames

FileReaderr=newFileReader(args[i]);//Openfilereaderobjectxr.parse(newInputSource(r));//parsethefileopened

}

}

}

XPath表示XML路径语言,它是一种访问XML文档各部分的语言,访问方式类似于文件系统用路径名和文件名访问文件。

在文件系统中,路径\Courses\CSE445\Assignments\assignment1.doc标识文件“assignment1.doc”,它在CSE445目录的Assignments子目录里,而CSE445目录又是Courses目录的子目录。4.3XPath在XPath中,XML文档被看作是一棵有根树,一个路径被称为一个XPath表达式。一个表达式返回一个对象,可以是以下类型之一:

①一组节点(节点有可能为空);

②一个字符串;

③一个布尔值(真或假);

④一个数字。

可以使用从根节点到所选节点(元素)的完整路径或者一个本地路径定义一个表达式。例如,/Courses/Course标识了根元素Courses的子节点中所有名为Course的元素(节点)。可以用一个带“@”字符的表达式标识属性。例如,/Courses/Course/@Image,标识了所有名为Image且属于Course元素的属性(非元素),而Course元素又是根元素Courses的子元素。

XPath支持无路径搜索。在一个名称前加上双斜线//将导致运行时在整个文档中搜索该名称。例如,表达式//Course标识文档中所有的Course元素。无论元素在文档的什么地方,通过前缀表达式//都能找到它。XPath也支持文件系统中使用的通配符。表达式/Courses/*表示选择Courses的所有子元素,而表达式/Courses/Course/@*表示选择所有属于Course的属性。

可以应用筛选运算符[]选择一个或多个满足给定条件的节点,这个筛选运算符可以用于属性和元素。例如,表达式/Courses/Course[Cap>40]表示返回Cap值大于40的那些Course元素,而表达式/Courses/Course[Level=′Senior′]表示返回所有Senior层的Course元素。当表达式返回一组名称相同的节点时,将以一个集合的形式返回。例如,在所举的例子中,表达式//Course返回两个Course节点。可以将筛选运算符作为索引运算符,指定想要从集合中选择的那项。请注意,索引从1开始,而不是0。表达式//Course[2]返回第二个Course节点。所选节点的顺序与它们在XML文档中的顺序相同。可以将索引运算符与其他运算符结合起来,例如,//Course[2]/Cap表示在第二个Course中选择Cap。可用的算术运算符包括:

=(等于操作符)例如://Course[.=′Senior′]

!=(不等于操作符)例如://Name[@Short!=′IntrotoPL′]

<=(小于等于操作符)例如://Course[Cap<=40]<(小于操作符)例如://Course[Cap<50]

>=(大于等于操作符)例如://Course[Cap>=40]

>(大于操作符)例如://Course[Cap>60]

可以用逻辑运算符:“and”、“or”和“not”把多个表达式连接起来创建复合表达式,例如:

//Course[Level=′Senior′andCap<50]

//Course[Room=′BYAC110′orCap>=80orCode!=′CSE445′]

//Course[not(Room=′BYAC210′)]与DOS文件系统相似,在XPath中可以用一个点“.”表示当前目录,用两个点“..”表示父目录。

在XPath规范中对XPath语言及其应用进行了完整描述,这个规范可以在/TR/xpath找到,本节只给出了主要特征。

Xpath也可以集成在不同的编程环境中。在.Net中,System.Xml.Xpath名字空间包含一组类,用于支持C#应用中的XPath操作。这些类可以按下列步骤创建查询对象、执行查询操作并存储查询返回的数据。(1)XPathDocument类从一个XML文档创建出一个封装的XPath文档。这个类包含多个构造函数,用于从流、URL、文件、TextReader或XmlReader实例化一个XPathDocument类。下面的语句创建一个XPathDocument对象,并用Courses.xml初始化它:

XPathDocumentdx=newXPathDocument("Courses.xml");

(2)XPathNavigator类提供了执行Xpath查询的机制。下面的语句用步骤1中的XpathDocument创建一个XPathNavigator对象。XPathNavigatornav=dx.CreateNavigator();

(3)XPathNodeIterator类表示由XPath查询所产生的节点集,并允许用户重复使用。XpathNodeIterator包含几个执行Xpath查询的方法。

①Evaluate方法可以执行任何Xpath表达式。根据表达式和在XML文档中存储的数据类型,Evaluate方法返回的对象可以是一个字符串、一个浮点数、一个布尔值或一个XPathNodeIterator(节点集)。

②Select方法专门用于返回一个节点集的表达式,并从节点集中选择指定的节点。下面的语句用Select方法创建一个与表达式∥Course相匹配的所有节点的集合,然后打印集合中的节点数。

XPathNodeIteratoriterator=nav.Select("//Course");

Console.WriteLine("Selectfinds{0},nodes",iterator.Count);

在XPathNavigator类中有一系列的属性和方法,允许用户访问返回的数据。例如,Current属性代表当前节点,可以调用多个Move方法从当前位置向任意方向移动,如:上、下、左、右。下面的程序使用了一些方法和类。usingSystem;

usingSystem.Xml.XPath;

classMyApp{

staticvoidMain(){XpathDocumentxdoc=newXPathDocument("/WSRepository/xml/Courses.xml");

XPathNavigatorxpdoc=xdoc.CreateNavigator();

XPathNodeIteratorxset=xpdoc.Select("/Courses/Course");

while(xset.MoveNext()){

XPathNodeIteratorxnode=xset.Current.Select("Name");

xnode.MoveNext();

stringshortName=xnode.Current.GetAttribute("Short","");stringcourseName=xnode.Current.Value;

xnode=xset.Current.Select("Code");

xnode.MoveNext();

stringcourseCode=xnode.Current.Value;

xnode=xset.Current.Select("Cap");

xnode.MoveNext();

doublecourseCap=xnode.Current.ValueAsDouble;

Console.WriteLine("Name={0}\nShortName={1}\nCode={2}\nCap={3}\n",

courseName,shortName,courseCode,courseCap);

}}

}

程序的输出结果为:

Name=IntroductiontoProgrammingLanguages

ShortName=IntrotoPL

Code=CSE240

Cap=82

Name=DistributedSoftwareDevelopment

ShortName=DistrSoftDev

Code=CSE445

Cap=40

为什么XML需要类型定义语言呢?XML是用来定义基于XML语言的一种元语言。每一种类型或模式定义都定义了一种新的基于XML的语言,包括词汇、语法和语义(规则)。正如我们所看到的,在XML文档中,一条信息可以用不同的方式和不同的标签(词汇)进行编码。4.4XML类型定义语言当信息从产生地传到目的地时,接收者(或接收程序)需要知道文档如何组织、允许哪些标签、格式是否确实与XML标准一致、XML文件中的数据是否有效。例如,考虑以下两组XML数据,很明显,左边的数据不符合表示时间的约束。不太明显的是,右边的数据如何?是否可以接受?

<time>

<hour>15</hour>

<minute>72</minute>

<second>-5</second>

</time><time>

<hour>15</hour>

<minute>20</minute>

<second>5</second>

</time>

使用军用时间(MilitaryTime)是可以接受的,但如果使用标准时间是不可以接受的。文档类型和模式定义语言允许XML文档作者给他们的文档定义语法和语义(业务规则),这些文档可以通过文档接收者确认,如图4.5所示。基于类型和模式定义文件创建的XML文件是类型定义的一个实例。

图4.5以定义文档为参考确认一个XML实例文件4.4.1XML文档类型定义(DTD)

DTD(文档类型定义)文件保存XML文档的结构和语法信息。可以用一个单独的文件(外部DTD)或XML文档自身(内部DTD)定义一个DTD文件。在Internet上存储的外部DTD可以被多个XML文档共享。

一个DTD文档包含一个根元素和一系列文档类型声明,每一个声明称为一个元素:

<!DOCTYPErootelement

[doctypedeclarations

]>

每个元素用下列语法定义:

<!ELEMENTelement-namecontent-model>

通过定义,被命名的XML文档中的所有元素与一个内容模型相关联。

内容模型可以是下列之一:

EMPTY:没有允许的内容;

ANY:允许任何内容; PCDATA:解析字符数据和某些运算符的组合。

允许组合的运算符包括:

|(选择),例如(a|b|c);

,(顺序),例如(a,b,c);

?(可选的),例如a?;

*(0个或多个),例如b*;

+(1个或多个),例如c+。

定义教师的XML文档和相应的DTD文件如图4.6。

图4.6一个XML文件与一个内部DTD定义DTD文件可以单独存储在URL站点。实例文件可以通过引用指向DTD文件,如下面代码所示。

定义教师及其属性的XML文档的DTD文件如下:

<?xmlversion=′1.0′encoding=′UTF-8′>

<!DOCTYPEinstructorSYSTEM"/WSRepository/xml/instructor.dtd">

<instructor>

<name>

<first>Yinong</first><last>Chen</last></name>

<course>DistributedSoftwareDevelopment</course>

<officeHours>4</officeHours>

<phone>480-9658300</phone>

</instructor>

用下面的语法,DTD定义元素的属性列表:

<!EMEMENTcourse(#PCDATA)>

<!ATTLISTcourselevelCDATA#REQUIRED

textCDATA#IMPLIED

campCDATA"Tempe">

在定义中,#REQUIRED是指必须提供该属性。#IMPLIED是指该属性是可选的,并且如果不提供属性,也没有默认属性。camp属性的默认值是“Tempe”,如果实例文档为该属性不提供属性值的话,将会用到“Tempe”。例如,下面的例子是上述定义的一个实例。

<courselevel="senior"

text="Service-OrientedArchitecture&Computing"

camp="West">DistributedSoftwareDevelopment

</course>

由于属性值是引用的,并且任何引用文本不会被解析,所以course元素必须是PCDATA类型的,而属性可以是PCDATA或CDATA类型。4.4.2XML模式

在定义XML文档的结构(语法)和类型上,XML模式(Schema)与DTD相比是一个更好的选择。与DTD相比,模式的优点包括:

①DTD不是基于XML的,并且需要单独的工具处理DTD文档,而XMLSchema是基于XML的,处理XML文档的工具也可以处理XML模式文档。

②XML模式是可扩展和可重用的。可以方便地添加新类型、约束现有类型,并组合现有的模式。③DTD限制于字符串类型。XML模式类似于典型的编程语言,支持基本类型,包括整型、浮点型、字符串,并可以定义其他复杂类型。

XML模式的名字空间包括用来构造模式的元素和数据类型,这些元素和数据类型包括:

schema;

element; complexType;

sequence;

Boolean;

integer;

string。

XML模式有44个内置类型,其中包括19个简单(基本)类型和25个派生的复杂类型。用户可以进一步定义简单类型和复杂类型。在XML文档中,Schema作为一个元素引入,并带有开放标签<schema>及许多可选属性,例如,指出来源和版本。

<schemaxmlns="/2000/10/XMLSchema"version"1.0">

声明指出schema是W3C网站定义的XMLSchema。前缀xsd说明了schema的名字空间(域)。与DTD相比,XML模式提供了从简单到复杂的更强的数据类型。类似编程语言,可以定义结构类型。例如,我们可以如下定义一个personnelType类型:<complexTypename="personnelType">

<sequence>

<elementname="firstname"type="string"/>

<elementname="lastname"type="string"/>

<elementname="id"type="integer"/>

</sequence>

<attributename="salary"type"Float"use="required"/>

</complexType>

下面例子定义了2个复杂类型:“Bookstore”和“Book”,以及5个简单类型:“Title”,“Author”,“Year”,“ISBN”,“Publisher”。

<?xmlversion="1.0"encoding="UTF8"?>

<xsd:schemaxmlns:xsd=/2001/XMLSchematargetNamespace="http://

/WSRepository/xml/bookstore"

xmlns="/WSRepository/xml/bookstore"

elementFormDefault="qualified"

attributeFormDefault="unqualified"><xsd:elementname="Bookstore">

<xsd:complexType>

<xsd:sequence>

<xsd:elementname="Book"minOccurs="1"maxOccurs="unbounded"/>

</xsd:sequence>

</xsd:complexType>

</xsd:element>

<xsd:elementname="Book">

<xsd:complexType><xsd:sequence>

<xsd:elementname="Title"minOccurs="1"maxOccurs="1"/>

<xsd:elementname="Author"minOccurs="1"maxOccurs="unbounded"/>

<xsd:elementname="Year"minOccurs="0"maxOccurs="1"/>

<xsd:elementname="ISBN"minOccurs="0"maxOccurs="1"/>

</xsd:sequence>

</xsd:complexType></xsd:element>

<xsd:elementname="Title"type="xsd:string"/>

<xsd:elementname="Author"type="xsd:string"/>

<xsd:elementname="Year"type="xsd:integer"/>

<xsd:elementname="ISBN"type="xsd:string"/>

<xsd:elementname="Publisher"type="xsd:string"/>

</xsd:schema>

除了用约束“minOccurs”和“maxOccurs”限定元素允许的出现次数外,XML模式提供了3个运算符来定义复杂类型的可选成员:①sequence:成员必须按给定的顺序出现;

②choice:只允许成员列表中的一个成员;

③all:所有成员必须出现(除非minOccurs="0"),但可以按任意顺序出现。

下面的例子说明了这些运算符的使用:

<xsd:elementname="Book">

<xsd:complexType>

<xsd:sequence>

<xsd:elementname="Title"/><xsd:elementname="Author"/>

<xsd:elementname="Year"/>

<xsd:choice>

<xsd:elementname="ISBN-10"/>

<xsd:elementname="ISBN-13"/>

</xsd:choice>

</xsd:sequence>

</xsd:complexType>

</xsd:elementname="Book">类似于面向对象编程语言的继承属性,XML模式可以用继承定义一个基于现有类型的新类型。可以扩展现有类型,而不用重新定义现有类型的元素和属性。例如,我们可以在personnelType类型的基础上定义一个researcherType类型。

<complexTypename="researchType">

<extensionbase="personnelType">

<sequence>

<elementname="researchInterests"type="string"/>

</sequence><attributename="rank"type"string"/use="optional">

</extension>

</complexType>

在扩展类型中,可给基类型添加元素和属性。扩展定义等价于下面的定义:

<complexTypename="researchType">

<sequence>

<elementname="firstname"type="string"/>

<elementname="lastname"type="string"/><elementname="id"type="integer"/>

<elementname="researchInterests"type="string"/>

</sequence>

<attributename="salary"type"Float"use="required">

<attributename="rank"type"string"use="optional">

</complexType>

使用extension是一种定义类型的更好的方法:

①更加简洁;

②易于维护,例如,如果修改了基类型,则扩展类型会自动更新;

③把层次树中所有相关类型关联起来,树中直接基类型是扩展类型的父类型。4.4.3名字空间

一个XML文档可以使用多个由不同提供商定义的DTD和模式。显然,在不同的情况下,这些DTD和模式可以使用相同的名称。名字空间用来限制名称的范围,因此它消除了冲突。例如,在http://www.bu.ac.uk网站上,一个英国大学的模式buSchema用facult表示大学的组成单元,而在网站上,一个美国大学的模式asuSchema用facult表示大学的员工。为了区分这两个含义,我们为每个文档定义一个名字空间。在下面的代码块中,定义并使用了bu和asu这个两个名字空间。<?xmlversion="1.0"encoding="UTF-8"?>

xmlns:bu="http://www.bu.ac.uk/buSchema"

xmlns:asu="http://www.bu.ac.uk/asuSchema"

<personnel>

<bu:facultybu:name="Engineering"/>

<asu:facultyasu:name="JoeMiller"/>

</personnel>名字空间声明为元素的属性。它把一个前缀名(限定词)和一个模式定义绑定,然后在任何需要的地方使用前缀。名字空间经常在根元素中声明,因此声明的名字空间的范围是整个文档。但是,名字空间也可以在XML文档中的任何元素中声明,这时,它的范围只是整个元素。名字空间可以被重载,使用前缀名(限定词)声明的内部名字空间重载外部的名字空间。作为例子,图4.7是为bookstoreXMLschema定义的名字空间,以及在名字空间定义的属性。如果你想使用名字空间的一个元素,并且这个元素频繁出现,那么重复限定将会非常麻烦。在这种情况下,你可以声明一个默认的名字空间。一旦你定义了一个默认的名字空间,作用域里所有未明确限定的元素都被隐含限定,也就是,认定它来源于默认的名字空间。请注意,在任何时候,只有一个默认的名字空间。

图4.7一个具有内部DTD定义的XML文件可以用语法“xmlnsmyNamespace=….”定义名字空间的名称。如何声明一个默认的名字空间?我们用相同的语法,但没有“myNamespace”。在图4.7中,默认的名字空间如下定义:

xmlns="/share/services/xml/bookstore".

前缀名字空间和默认名字空间不用于元素的属性。要把名字空间用于属性,属性必须被明确限定。在下面的例子中,属性“edition”没有名字空间,而属性“cover”与名字空间bs相关联。<Bookxmlns="/WSRepository/xml">

<Titlebs:cover="paperback">ProgrammingLanguages</Title><Author>YinongChen</Author>

<Author>W.T.Tsai</Author>

<Yearedition="2">2006</Year>

<ISBN>0-7575-2974-7</ISBN>

</Book>我们还可以定义目标名字空间,它包括定义目标名字空间时使用的名字空间。在图4.7的例子中:

xmlns="/share/services/xml/bookstore".

将包括以下两个名字空间定义的词汇:

/2001/XMLSchema

xmlns="/share/services/xml/bookstore".

定义模式的目的是使用该模式定义XML实例。使用上面定义的bookstore模式,我们可以定义如下的实例(XML)。<?xmlversion="1.0"?>

<Bookstorexmlns="/WSRepository/xml"

xmlnsbs="/WSRepository/xml/bookstore.xsd"

xmlns:xsi="/2001/XMLSchema-instance"

xsi:schemaLocation="/WSRepository/xml/bookstore.xsd"><Book>

<Title>

bs:cover=paperbackIntroductiontoProgrammingLanguages

</Title>

<Author>YinongChen</Author>

<Author>W.T.Tsai</Author>

<Year>edition="2"2006</Year>

<ISBN>0-7575-2974-7</ISBN>

<Size>A4</Size></Book>

<Book>

<Title>DistributedService-OrientedSoftwareDevelopment</Title>

<Author>YinongChen</Author>

<Author>W.T.Tsai</Author>

<Year>2008</Year>

<ISBN>978-0-7575-5273-1</ISBN>

<Size>A4</Size>

</Book></Bookstore>

请注意,前缀名字空间和默认命名空间没有用于元素的属性。要把名字空间用于属性,属性必须被明确限定。在上面的例子中,属性“edition”没有名字空间,而属性“cover”与名字空间bs相关联。由于属性通常被认为是补充信息,所以它们不会被XML确认器检查。在图4.7的名字空间定义中,下面的句子:

elementFormDefault="qualified"

attributeFormDefault="unqualified">说明了所有的元素必须被限定,而属性不需要被限定。

总结名字空间这一部分,我们从XML模式的W3C标准定义XMLschema名字空间/2001/XMLSchema开始,并用它定义了bookstore的模式,还定义了一个

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论