以文本方式查看主题

-  中文XML论坛 - 专业的XML技术讨论区  (http://bbs.xml.org.cn/index.asp)
--  『 XML基础 』  (http://bbs.xml.org.cn/list.asp?boardid=1)
----  XML初学进阶学习笔记[原创](整理完整版)  (http://bbs.xml.org.cn/dispbbs.asp?boardid=1&rootid=&id=28676)


--  作者:卷积内核
--  发布时间:3/15/2006 10:20:00 AM

--  XML初学进阶学习笔记[原创](整理完整版)
简体中文码:GB2312
    繁体中文码:BIG5
    西欧字符: UTF-8


1、一般实体

我们前面说到的那个信件署名就是一般实体。定义一般实体的格式如下:
<!ENTITY 实体名 "文本内容"〉  

关于刚才的信件署名的实体定义如下:

<!ENTITY lettersign
"张三
某网络公司销售部门
北京市海淀区中关村88号,100000"〉  

另外,你也可以指定一个实体代替一个外部文件的内容,此时要使用SYSTEM这个关键字。例如:

<!ENTITY lettersign
SYSTEM "http://www.mydomain.com/lettersign.xml"〉  

在这个例子中,XML处理器将用指定文件的内容来替换实体指示。


2、参数实体
与一般实体相同,参数实体既可以是内部的也可以是外部的。不过,参数实体只用在DTD中。
参数实体的格式与一般实体很类似,只不过中间要加上“%”符。

<!ENTITY % 实体名 "文本内容"〉  


3、实体的使用包括两部分:实体声明和实体引用。

4、实体声明
对于实体的声明应该放在文件类型DOCTYPE中。DOCTYPE一般放在文件头(即XML声明和DTD)之后,
XML元素之前。这样一来,XML文件就变为下面的形式:

<?xml version="1.0"?>
<!DOCTYPE 文件根元素名 [
    实体声明部分
]>
<文件根元素名>
    具体数据内容
</文件根元素名>

5、实体引用
说到实体引用,大家可能想起前面我们曾用“&lt;”代表字符“〈”。不错,这就是一个实体引用。

简而言之,实体引用指的是引用一个在实体声明中已经声明过的一个实体。实体引用的形式很简单:

&实体名;


6、实体引用有以下几点规则一定要注意:

在引用XML实体之前,必须已经在XML文件中对此实体进行过声明;
在实体引用中不能出现空格。也就是说,& lettersign;和&letterhead ;的用法都会引起错误。
尽管在一个实体中可以再引用其它实体,但是不能出现循环引用。也就是说,一个实体不能引用它自己;
同样,也不能出现实体A引用实体B,然后实体B再反过来引用实体A的情况。
实体引用不能在DOCTYPE声明中出现。
实体引用的文本必须是形式良好的XML。
同样,参数实体的引用与一般实体的引用大同小异,只是要把实体前的符号&换为%就可以了,形式是:

%实体名;

7、实体引用不仅可以出现在字符数据中,还可以出现在标记的属性中。例如下面这个例子:

<联系人 公司=“B公司” 地址=“&B公司地址;”>  

如果在属性中出现实体引用,不但要遵守前面所述的实体引用的种种规则,还要注意以下两点:

在标记属性中不能引用一个外部实体。
引用的文本中不能出现字符“<”,否则替换后就不再是一个“形式良好的”XML文件了。
通过这一节的讲述,想必大家已然了解:实体主要是用来代替字符数据的,它可以节省大量的录入工作。

8、使用外部DTD时,要在DOCTYPE中使用关键字SYSTEM。实际上,SYSTEM不是引用外部DTD的唯一方法,
这个关键字主要用于引用一个作者或组织所编写的众多XML文件中通用的DTD。还存在一种外部DTD,
它是一个由权威机构制订的,提供给特定行业或公众使用的DTD。因此,另一个引用外部DTD的办法是使用关键字PUBLIC,
引用这一类公开给公众使用的DTD。

当使用关键字PUBLIC进行引用时,这个外部DTD还需要得到一个标识名。引用公共DTD的形式为:

<!DOCTYPE 根元素 PUBLIC "DTD名称" "外部DTD的URL">


9、这个DTD标识的命名规则和XML文件的命名规则稍有不同。具体地说,DTD名称只能包含字母、
数字、空格和下面的符号:_%$#@()+:=/!*;?。同时,DTD名称还必须符合一些标准的规定。
例如,ISO标准的DTD以“ISO”三个字母开头;被改进的非ISO标准的DTD以加号“+”开头;未被改进的非ISO标准的DTD以减号“-”开头。

无论是哪一种情况,开始部分后面都跟着两个斜杠“//”及DTD所有者的名称。在这个名称之后又是两个斜杠“//”,
再然后是DTD所描述的文件的类型。最后,在又一对斜杠之后是语言的种类(参见ISO 639)。例如下面这个公用DTD的引用:

<!DOCTYPE 联系人列表 PUBLIC "-//Luna Dong//Contact Data//CN"
"http://www.mydomain.com/dtds/fclml.dtd">

10、除了根元素外,在定义其它元素时使用关键字ANY都是不好的习惯。一般来说,在写一个XML文件时需要严格遵循DTD的规则,
这时,一个定义明确的DTD,虽然表面上似乎充满了条条框框,但实际上会使你在书写XML文件时有规可循,
反而方便了你的工作和语法分析器的工作。相反,一个在元素定义中充满了ANY的DTD,反而可能会搞得你不知所措,一头雾水。


--  作者:卷积内核
--  发布时间:3/15/2006 10:20:00 AM

--  
11、在定义元素时,ETD的顺序是无关紧要的。因此
    <!ELEMENT 姓名(#PCDATA)>    
    <!ELEMENT 联系人列表 ANY>
    <!ELEMENT 联系人(姓名)>

    <!ELEMENT 联系人列表 ANY>
    <!ELEMENT 联系人(姓名)>
    <!ELEMENT 姓名(#PCDATA)>    
所定义的文件结构是完全相同的。


12、还有一点要注意,不能对不同的元素使用相同的元素名,即便这些元素的内容、包含的子元素不同也不行,
因为它只会引起文件各个元素的混淆,使文件的可读性大打折扣。例如:
    <!ELEMENT 联系人列表 ANY>
    <!ELEMENT 联系人(姓名)>
    <!ELEMENT 联系人(EMAIL)>
    <!ELEMENT 姓名(#PCDATA)>
    <!ELEMENT EMAIL(#PCDATA)>
在这个例子中,对“联系人”的重复定义,会引起错误。

13、最后再次强调一下元素的命名。元素名的第一个字母必须是字母、或下划线(_)、或冒号(:),
后跟字母、数字、句号(.)、冒号、下划线、连结号(-)的组合,并且不能包含空白符,不能以“xml”开头。
另外,尽管元素的第一个字母使用冒号是合法的,但最好避免这样做,因为它会引起混淆。再有需要注意的是,
尽管XML1.0标准允许使用任何长度的文件名,但是实际的XML处理器常常会限制标记名的长度。

14、
学过《编译原理》的应该对正则表达式都非常理解拉,这里用法相同。

元 字 符        含    义

  +         出现一次或多次
  *         出现零次或多次
  ?        可选,不出现或出现一次
()       一组要共同匹配的表达式
  |            OR,或
  ,        AND,要求严格遵从顺序要求
  元素A
  元素B
  元素C    元素列表,无须遵从顺序要求


15、
    <!ELEMENT 联系人(姓名, EMAIL)>
    <!ELEMENT 姓名(#PCDATA)>
    <!ELEMENT EMAIL(#PCDATA)>
    如果我们使用逗号“,”来分隔两个子元素,那么XML文件中,元素“姓名”就必须出现在元素“EMAIL”前面。反之,可以无序。

16、XML正则表达式的匹配原则不允许循环逻辑。所以,OR的意思是或者选这个或者选那个,但不能两个都选,也不能两个都不选。

17、注意:在一个组中,只允许使用一种连接符(例如“,”或“|”)。因此,象下面这样定义的DTD是不合法的:

<!ELEMENT 联系人(姓名,电话|EMAIL)>

要想使用多种连接符,只有通过创建子组的方式,使用

<!ELEMENT 联系人(姓名,(电话|EMAIL))>

前面我们已经介绍了所有可能用到的子元素的排列状况。不过,还有一种情况没有说,那就是,一个元素中不包含任何子元素,也不包含纯文本。

对于这种情况,我们可以定义一个空标记。当然,定义这样一个标记很简单,你只需要使用关键字EMPTY就可以了,例如:

    <!ELEMENT HR EMPTY>

这样,在你的XML文件中,就可以使用一个空元素<HR/>。

18、IDREF类型允许一个元素的属性使用文件中的另一个元素,方法就是把那个元素的ID标识值作为该属性的取值。

19、参数实体专门用在DTD中。定义方式是:

<!ENTITY % 实体名 "实体内容">

或: schema

<!ENTITY % 实体名 SYSTEM "外部文件名">

引用方式为:

%实体名;

20、使用参数实体,可以方便元素和属性的声明。例如:

<!ENTITY % TAG_NAMES "姓名 | EMAIL | 电话 | 地址">
<!ELEMENT 个人联系信息 (%TAG_NAMES; | 生日)>
<!ELEMENT 客户联系信息 (%TAG_NAMES; | 公司名)>


--  作者:卷积内核
--  发布时间:3/15/2006 10:21:00 AM

--  
21、dt:type
dt:type指定所声明属性的数据类型,它除了支持DTD中包含的全部十大数据类型外,还支持一些扩展属性,在下一小节会详细讲述。
Schema中的十个基本属性与DTD中属性的对应关系请见下表:


Schema中基本类型        DTD中数据类型
string                   #PCDATA
enumeration              ENUMERATED
id                       ID
idref                    IDREF
idrefs                   IDREFS
nmtoken                  NMTOKEN
nmtokens                 NMTOKENS
entity                   ENTITY
entities                 EMTITIES
notation                 NOTATION

注意,当dt:type取值为"enumeration"时,后面的dt:value必须列出所有可能的取值。

22、attribute实际上是对该Schema中AttributeType声明的引用,而具体引用什么属性类型,
关键就要靠type属性了。type唯一指定了要引用的属性类型,
因此其取值必须同某个AttributeType元素中name属性的取值严格一致。
其它两个属性与AttributeType中相应属性的含义相同,
default指定该属性类型的缺省取值,
required指定该属性对于引用它的元素是否是必须的。
如果和同一个属性相对应的AttributeType和attribute中都对default和required给出了定义,
则在attribute中的取值具有更高的优先级。

23、XML较之HTML最根本的差别在于XML是定义置标语言的元语言,
而HTML仅仅是由SGML元置标语言定义的一个实例语言。利用XML元置标语言,
定义各种各样的XML实例的活动是相当开放的。针对不同的应用方向,
每设计一个XML的DTD,一种新的置标语言便随之诞生。
在各种各样XML实例置标语言如雨后春笋般不断涌现的过程中,
将会产生这样一种应用需求,即在一个XML文档中,包含由多个DTD描述的元素。
这个想法显然是达到“物尽其用”的一个好办法,它帮助我们最大程度地利用了现有的资源,
正所谓“海纳百川,有容乃大”。

24、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样式)。


25、DOM的全称是Document Object Model,也即文档对象模型。在应用程序中,
基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称DOM树),
应用程序正是通过对这个对象模型的操作,来实现对XML文档数据的操作。通过DOM接口,
应用程序可以在任何时候访问XML文档中的任何一部分数据,因此,这种利用DOM接口的机制也被称作随机访问机制。

DOM接口提供了一种通过分层对象模型来访问XML文档信息的方式,
这些分层对象模型依据XML的文档结构形成了一棵节点树。
无论XML文档中所描述的是什么类型的信息,即便是制表数据、项目列表或一个文档,
利用DOM所生成的模型都是节点树的形式。也就是说,DOM强制使用树模型来访问XML文档中的信息。
由于XML本质上就是一种分层结构,所以这种描述方法是相当有效的。

26、SAX的全称是Simple APIs for XML,也即XML简单应用程序接口。与DOM不同,
SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式。当使用SAX分析器对XML文档进行分析时,
会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问,
因而SAX接口也被称作事件驱动接口。


--  作者:卷积内核
--  发布时间:3/15/2006 10:22:00 AM

--  
27、XML DOM初学者指南


总述:本文主要讨论如何利用XMLDOM访问和维护XML文档,这个XMLDOM由Microsoft 解析器实现。

目录:

简介

DOM是什么

如何使用DOM

如何Load一个文档

处理错误

如何从XML文档中取得信息

如何遍历XML文档

下一步该干什么

简介:

作为VB的开发者你可能会接触eXtensible Markup Language (XML)文档。你现在想处理XML文档并把它集成到你的方案中。你可以自己编程解析,把它当普通文本文档处理,但这样作太没有效率了,没有利用XML的强大之处:它可以结构化的表示数据。

从XML文件中获得信息最好的办法是利用XML解析器。解析器,简单的讲,就是一个软件,它可以使XML文件中的数据易于使用。作为VB的开发者,你可能想得到一个支持Document Object Model (DOM)的解析器。DOM描述了一系列标准的访问XML和HTML文档的方法,这些方法解析器应该实现。一个支持DOM的解析器应该把XML中的数据变成一系列对象,这样就可以对这些对象二次编程。在这篇文章中,你会学习如何利用Microsoft 解析器(Msxml.dll)实现的DOM结构访问和维护XML文档。

在我们继续前进时,让我们先看一段XML代码来了解这个解析器怎样使我们生活变得容易。下面这个叫cds.xml的文档用来表示一个唱片的各个项目,每个项目包含象主唱,标题,音轨这样的信息。

<? xml version="1.0"?>

<! DOCTYPE compactdiscs SYSTEM "cds.dtd">

<compactdiscs>

<compactdisc>

<artist type="individual">Frank Sinatra</artist>

<title numberoftracks="4">In The Wee Small Hours</title>

<tracks>

<track>In The Wee Small Hours</track>

<track>Mood Indigo</track>

<track>Glad To Be Unhappy</track>

<track>I Get Along Without You Very Well</track>

</tracks>

<price>$12.99</price>

</compactdisc>

<compactdisc>

<artist type="band">The Offspring</artist>

<title numberoftracks="5">Americana</title>

<tracks>

<track>Welcome</track>

<track>Have You Ever</track>

<track>Staring At The Sun</track>

<track>Pretty Fly (For A White Guy)</track>

</tracks>

<price>$12.99</price>

</compactdisc>

</compactdiscs>

上面的文档的第二行引用了一个外部DTD(文档类型描述),DTD描述了一个特定类型的XML的层次结构和能包括的内容。XML解析器利用DTD来验证XML文档的正确性。DTD只是你用来让解析器验证XML文档是否合法的办法的一种,另一个越来越受欢迎的方法是XML Schemas,它用XML来描述Schemas而不是DTD。与DTD不同的是, Schema是用XML来描述的,也就是使用它自己的"有趣的"语法。

下面的文档是cds.xml用到的cds.dtd。

<! ELEMENT compactdiscs (compactdisc*)>

<! ELEMENT compactdisc (artist, title, tracks, price)>

<! ENTITY % Type "individual | band">

<! ELEMENT artist (#PCDATA)>

<! ATTLIST artist type (%Type;) #REQUIRED>

<! ELEMENT title (#PCDATA)>

<! ATTLIST title numberoftracks CDATA #REQUIRED>

<! ELEMENT tracks (track*)>

<! ELEMENT price (#PCDATA)>

<!ELEMENT track (#PCDATA)>

本文不会对DTD和XML Schemas讨论过深,基于XML-DATA的XML Schema Reference已提交给W3c。

DOM是什么:

 

XML DOM结构将XML文档的内容实现为一个对象模型。W3C的DOM Level 1 说明定义了DOM结构如何实现属性,方法,事件等等。微软的DOM实现完全支持W3C标准,并且还有许多使程序更容易访问XML文件的新增特点。

如何使用DOM

要使用DOM,需要创建一个XML解析器的实例。微软公司在Msxml.dll中创建了一系列标准的COM接口来使创建实例变得可能。Msxml.dll中包含了类型库和可应用的代码,这些你可以用来处理XML文件。如果你使用可实现脚本的客户端,比如VBScript 和IE,你可以使用CreateObject方法来得到解析器的实例。

Set objParser = CreateObject( "Microsoft.XMLDOM")

如果你使用ASP (Active Server Page),你使用Server.CreateObject方法。

Set objParser = Server.CreateObject( "Microsoft.XMLDOM" )

如果你在使用VB,你可以创建一个对MSXML类型库的引用,这样就可以访问DOM。要在VB6.0中使用MSXML,操作如下:

打开Project References项
从COM对象中选择Microsoft XML, version 2.0,如果你找不到此项,你需要得到它。
你可以创建一个解析器的实例了。
Dim xDoc As MSXML.DOMDocument Set xDoc = New MSXML.DOMDocument

你可以通过两个途径获得Msxml.dll。

你可以安装IE5.0,MSXML解析器是其中集成的部件。
或者你可以到相关网站上下载它
一旦你建立了类型库的引用,你就可以执行解析,调入文档,总之,你可以处理XML文档了。

你可能有一些迷惑,我该干些什么?如果你打开MSXML库,用Visual Basic 6.0对象察看器察看其中的对象模型,你会发现很丰富。本文会告诉你如何利用DOMDocument类和IXMLDOMNode界面来访问XML文档。

 

如何Load一个文档:

要调入一个XML文档,先必须创建一个DOMDocument的实例。

Dim xDoc As MSXML.DOMDocument

Set xDoc = New MSXML.DOMDocument

当你获得一个合法的引用,你就可以用LOAD方法来调入一个文档。解析器可以从本地硬盘调入或者通过UNC和URL从网络上调入。

从硬盘调入如下:

If xDoc.Load("C:\My Documents\cds.xml") Then

' 文档调入成功

' 作我们喜欢作的事

Else

' 文档调入失败

End If

当你完成工作,你需要释放掉这个引用,MSXML没有直接实现CLOSE方法,你最好直接将它设置成Nothing来关闭它。

Set xDoc = Nothing

当你调用一个文档,默认是异步进行,你可以通过修改Async属性来更改它。如果你要操作文档,你必须先检查ReadyState属性来确认文档的状态,它会返回五种可能的结果。

状态
属性值

未初始化:调入文档没有开始
0

调入:Load方法正在执行
1

调入完成:Load 方法已经完成
2

交互阶段:DOM可以进行只读检验,数据部分解析
3

完成:数据完全解析,可以进行读/写操作。 4

MSXML解析器实现了一些有用的方法,你在调入一个大的文档时可以用这些方法追踪调入过程的状态。这些方法对从Internet上异步的调入文档也很有帮助。

要打开一个Internet上的文档,你需要提供绝对URL,并且必须加http://前缀。下面是一个例子。

xDoc.async = False

If xDoc.Load("http://www.develop.com/hp/brianr/cds.xml") Then

' 文档调入成功

' 作我们喜欢作的事

Else

' 文档调入失败

End If

将Async属性设置为False,这样在文档调入完成之前,解析器不会将控制权交给你的代码。如果把Async保存为True,你在访问文档时必须检查ReadyState属性或者利用DOMDocument的事件在文档可以访问时提示你的代码。

处理错误:

你的文档可能因为各种原因而调入失败,最常见的原因是提供给解析器的文档名不正确,另一个常见的原因是XML文档不合法。

默认的解析器会验证你的文档是否符合某个DTD 或者 schema,你可以不让解析器执行验证,在执行Load方法之前,将DOMDocument的属性ValidateOnParse为False。

Dim xDoc As MSXML.DOMDocument

Set xDoc = New MSXML.DOMDocument

xDoc.validateOnParse = False

If xDoc.Load("C:\My Documents\cds.xml") Then

' 文档调入成功

' 作我们喜欢作的事

Else

' 文档调入失败

End If

事先关闭验证功能不是个好主意,它会带来许多问题,至少它会是你提供错误格式的数据给你的用户。

你可以通过访问ParseError对象来从解析器那儿获得有关错误类型的信息。创建一个IXMLDOMParseError界面的引用,然后把它指向文档自身的ParseError对象。IXMLDOMParseError界面实现了七种属性来使你获得错误原因。

下面的例子显示了一个信息框,列出了ParseError对象中所有错误信息。

Dim xDoc As MSXML.DOMDocument

Set xDoc = New MSXML.DOMDocument

If xDoc.Load("C:\My Documents\cds.xml") Then

' 文档调入成功

' 作我们喜欢作的事

Else

' 文档调入失败

Dim strErrText As String

Dim xPE As MSXML.IXMLDOMParseError

' 获得parseError对象

Set xPE = xDoc.parseError

With xPE

strErrText = "你的XML Document 不能调入" & _

"原因是." & vbCrLf & _

"错误 #: " & .errorCode & ": " & xPE.reason & _

"Line #: " & .Line & vbCrLf & _

"Line Position: " & .linepos & vbCrLf & _

"Position In File: " & .filepos & vbCrLf & _

"Source Text: " & .srcText & vbCrLf & _

"Document URL: " & .url

End With

 

MsgBox strErrText, vbExclamation

End If

 

Set xPE = Nothing

你可以利用parseError对象来向你的用户报告错误信息,或者把它写入你个Log中,你还可以尝试自己解决遇到的问题。

 

如何从XML文档中取得信息:

一旦你成功的调入了文档,下一步就是如何从中获得信息了。当你操作文档时,你经常会用到IXMLDOMNode界面,你利用它来读/写各个分离的节点元素。在使用它之前,你必须先理解MSXML支持的13种节点元素类型,下面是最常用的几个。

 

DOM节点类型
举例

NODE_ELEMENT
<artist type="band">The Offspring</artist>

NODE_ATTRIBUTE
type="band">The Offspring

NODE_TEXT
The Offspring

NODE_PROCESSING_INSTRUCTION
<?xml version="1.0"?>

NODE_DOCUMENT_TYPE
<!DOCTYPE compactdiscs SYSTEM "cds.dtd">


 

你通过IXMLDOMNode界面实现的两个属性来访问节点的类型。NodeType属性列举了DOMNodeType所有项目(一些项目列举在上面的表格上)。另外,你可以用NodeTypeString属性来获得表示节点类型的字符串。

一旦你有了文档的DOM引用,你就可以遍历节点的层次。通过文档引用,你可以访问ChildNodes属性,它给出了一个自上而下的包含所有节点的目录。ChildNodes属性实现了IXMLDOMNodeList,它支持Visual Basic的For/Each结构,所以你可以列举出ChildNodes中的所有节点。另外,ChildNodes属性还实现了Level属性,它可以返回所有子节点的数目。

不只是文档对象有ChildNodes属性,每一个节点都有ChildNodes属性。因为如此,ChildNodes属性和IXMLDOMNode's HasChildNodes属性配合,使你非常方便的遍历文档,访问元素,属性,值。

值得一提的是,元素和元素值之间是父子关系。例如在 CDs XML文档中,元素<title>表示歌曲的名字,要知道<title>的值,你需要访问节点的属性NODE_TEXT。如果你发现一个节点有你感兴趣的数据,你可以访问它的属性,也可以通过ParentNode属性来访问它们的父节点。

如何遍历XML文档:

你能够遍历文档的节点是利用文档对象,因为XML本身就是层次结构,所以很容易编写递归代码来访问整个文档。

LoadDocument程序打开XML文档,然后调用另一个程序DisplayNode,它用来显示文档的结构。LoadDocument传递给正在打开的XML文档的ChildNodes属性一个引用作为它的参数,同时传递一个整数用来标示开始显示的层次级别。代码利用参数来格式化在Visual Basic文档结构显示窗口中的文本。

DisplayNode属性的函数会遍历文档寻找需要的NODE_TEXT节点类型串,一旦代码找到一个NODE_TEXT的节点,它会利用NodeValue属性来获得相应的文本串。另外,当前节点的ParentNode属性指向一个元素类型的节点。元素节点实现了一个NodeName属性,

 

NodeName和NodeValue属性会被显示。

如果一个节点还有子节点,通过检测HasChildNodes属性确认,DisplayNode就会调用自己知道遍历文档的全部。

 

下面这个DisplayNode程序用Debug.Print向Visual Basic窗口写入相关信息。

Public Sub LoadDocument()

Dim xDoc As MSXML.DOMDocument

Set xDoc = New MSXML.DOMDocument

xDoc.validateOnParse = False

If xDoc.Load("C:\My Documents\sample.xml") Then

' The document loaded successfully.

' Now do something intersting.

DisplayNode xDoc.childNodes, 0

Else

' The document failed to load.

' See the previous listing for error information.

End If

End Sub

Public Sub DisplayNode(ByRef Nodes As MSXML.IXMLDOMNodeList, _

ByVal Indent As Integer)

Dim xNode As MSXML.IXMLDOMNode

Indent = Indent + 2

 

For Each xNode In Nodes

If xNode.nodeType = NODE_TEXT Then

Debug.Print Space$(Indent) & xNode.parentNode.nodeName & _

":" & xNode.nodeValue

End If

If xNode.hasChildNodes Then

DisplayNode xNode.childNodes, Indent

End If

Next xNode

End Sub

DisplayNode用HasChildNodes属性来确认是否再次调用自己,你也可以用节点的Level属性,如果大于0,则有子节点。

下一步该干什么:

这仅仅是个开始,你现在可以更深的了解XML和Microsoft 解析器(Msxml.dll)。
你可以作一些有趣的事例如改变某个节点的值,搜索文档,建立你自己的文档等等。
访问 MSDN Online XML Developer Center以获得更多的例子,文章和下载。


--  作者:卷积内核
--  发布时间:3/15/2006 10:23:00 AM

--  
28、对于XML应用开发来说,DOM就是一个对象化的XML数据接口,一个与语言无关、与平台无关的标准接口规范。
它定义了HTML文档和XML文档的逻辑结构,给出了一种访问和处理HTML文档和XML文档的方法。
利用DOM,程序开发人员可以动态地创建文档,遍历文档结构,添加、修改、删除文档内容,
改变文档的显示方式等等。可以这样说,文档代表的是数据,而DOM则代表了如何去处理这些数据。
无论是在浏览器里还是在浏览器外,无论是在服务器上还是在客户端,只要有用到XML的地方,就会碰到对DOM的应用。

作为W3C的标准接口规范,目前,DOM由三部分组成,包括:核心(core)、HTML和XML。
核心部分是结构化文档比较底层对象的集合,这一部分所定义的对象已经完全可以
表达出任何HTML和XML文档中的数据了。HTML接口和XML接口两部分则是专为操作
具体的HTML文档和XML文档所提供的高级接口,使对这两类文件的操作更加方便。

目前,DOM有两个版本,一个是由W3C于1998年8月18日通过的DOM Level 1,
另一个则是正在制定过程中的DOM Level 2,W3C已于2000年3月7日通过了DOM Level 2的候选推荐版本。


29、在DOM接口规范中,有四个基本的接口:Document,Node,NodeList以及NamedNodeMap。
在这四个基本接口中,Document接口是对文档进行操作的入口,它是从Node接口继承过来的。
Node接口是其他大多数接口的父类,象Documet,Element,Attribute,
Text,Comment等接口都是从Node接口继承过来的。NodeList接口是一个节点的集合,
它包含了某个节点中的所有子节点。NamedNodeMap接口也是一个节点的集合,通过该接口,
可以建立节点名和节点之间的一一映射关系,从而利用节点名可以直接访问特定的节点。

Document接口代表了整个XML/HTML文档,因此,它是整棵文档树的根,
提供了对文档中的数据进行访问和操作的入口。

由于元素、文本节点、注释、处理指令等都不能脱离文档的上下文关系而独立存在,
所以在Document接口提供了创建其他节点对象的方法,通过该方法创建的节点
对象都有一个ownerDocument属性,用来表明当前节点是由谁所创建的以及节点同Document之间的联系。

Document节点是DOM树中的根节点,也即对XML文档进行操作的入口节点。通过Docuemt节点,
可以访问到文档中的其他节点,如处理指令、注释、文档类型以及XML文档的根元素节点等等。
另外,从上图我们还可以看出,在一棵DOM树中,Document节点可以包含多个处理指令、
多个注释作为其子节点,而文档类型节点和XML文档根元素节点都是唯一的。

30、Node接口在整个DOM树中具有举足轻重的地位,DOM接口中有很大一部分接口是
从Node接口继承过来的,例如,Element、Attr、CDATASection等接口,
都是从Node继承过来的。在DOM树中,Node接口代表了树中的一个节点。

31、NodeList接口提供了对节点集合的抽象定义,它并不包含如何实现这个节
点集的定义。NodeList用于表示有顺序关系的一组节点,比如某个节点的子节
点序列。另外,它还出现在一些方法的返回值中,例如GetNodeByName。

在DOM中,NodeList的对象是"live"的,换句话说,对文档的改变,会直接
反映到相关的NodeList对象中。例如,如果通过DOM获得一个NodeList对象,
该对象中包含了某个Element节点的所有子节点的集合,那么,当再
通过DOM对Element节点进行操作(添加、删除、改动节点中的子节点)时,
这些改变将会自动地反映到NodeList对象中,而不需DOM应用程序再做其他额外的操作。

NodeList中的每个item都可以通过一个索引来访问,该索引值从0开始。

32、实现了NamedNodeMap接口的对象中包含了可以通过名字来访问的一组节点的集合。
不过注意,NamedNodeMap并不是从NodeList继承过来的,它所包含的节点集中的节点是无序的。
尽管这些节点也可以通过索引来进行访问,但这只是提供了枚举NamedNodeMap中所包含节点的一种简单方法,
并不表明在DOM规范中为NamedNodeMap中的节点规定了一种排列顺序。

NamedNodeMap表示的是一组节点和其唯一名字的一一对应关系,这个接口主要用在属性节点的表示上。
与NodeList相同,在DOM中,NamedNodeMap对象也是"live"的。


33、利用DOM,程序开发人员可以动态地创建文档,遍历文档结构,添加、修改、删除文档内容等等。
我们将通过微软的XML分析器msxml,对DOM接口的这些应用做的介绍。

使用不同的编程语言创建Document对象的范例。

JScript:
var doc = new ActiveXObject("Microsoft.XMLDOM")

VB Script:
Dim docSet doc = CreateObject("Microsoft.XMLDOM")

VB:
Dim doc As ObjectSet
doc = CreateObject("Microsoft.XMLDOM")
或者
Dim doc As DOMDocumentSet doc = New DOMDocument

VC:
HRESULT hr = CoCreateInstance
(CLSID_DOMDocument,NULL,CLSCTX_INPROC_SERVER,IID_IXMLDocument(LPVOID*),&m_pXMLDocument);

34、Document的加载
不同的XML分析器所提供的加载XML文档的方法也不尽相同。
在微软的msxml中,提供了一个load方法来加载XML文档,建立DOM树同XML文档之间的关联。

依旧以联系人列表信息的XML文档.xml为例,可通过下述方式来加载文档:

Dim myDocumentSet myDocument = CreateObject("microsoft.xmldom")
myDocument.async = FalsemyDocument.load("client.xml")



--  作者:卷积内核
--  发布时间:3/15/2006 10:23:00 AM

--  
35、对DOM树的操作::

首先,我们要获取XML文档的根元素节点,用VBScript语言描述这个操作如下:

root = myDocument.documentElement

该语句的实际含义如下图黄色箭头所示。

在得到了文档的根元素节点之后,我们又将如何访问其他元素呢?以文档中的第二个person元素为例,
对该元素节点以及其子节点的访问可以通过下面的方式来实现:

personNode = root.childNodes.item(1)
nameNode = personNode.childNodes.item(0)
textNode = nameNode.childNodes.item(0)
theName = textNode.nodeValue

上述访问语句执行后,theName的值是"李四"。下图黄色箭头给出了这一访问过程的示意:

在上面的代码中,root是文档的根元素节点addressbook节点,
personNode和nameNode都是元素类型的节点,textNode是TEXT类型的节点,theName是一个字符串。

childNodes是NodeList类型的属性,item是NodeList接口中Node类型的属性,
通过item可以访问NodeList节点集合中的任意节点(这儿有一点需要注意,
当我们要访问根元素节点addressbook的第二个person子节点personNode时,
我们用的索引参数是"1",这是因为item中的索引参数是从0开始的,如果我们要访问节点集合中的第一个节点,则应该用item(0)来表示)。

在DOM规范中,要访问元素节点的文本内容,需要先得到元素节点的TEXT子节点,
再通过TEXT节点的属性获取文本内容。微软在实现DOM接口时对DOM进行了部分扩展,
可以通过元素类型节点的text属性直接获得元素中的文本内容。具体实用说明可以参考微软msdn中的帮助。

上面的例子给出了如何访问DOM树中的元素节点,
对于DOM树中的属性节点,访问方法略有不同,可以通过下面的语句来实现:

attr = node.attributes.getNamedItem("sex")
attrContent = attr.nodeValue

上述访问语句执行后,attrContent的值是"male"。下图用黄色箭头标出了这一访问的过程。

在上面的代码中,attr是属性类型的节点,attributes是NamedNodeMap类型的属性,
getNamedItem是NamedNodeMap接口中的方法。属性的内容可以通过属性节点的nodeValue来获得。

36、实现添加元素操作的语句如下:

node = root.childNodes.item(0)                 //确定位置
newNode = myDocument.createElement("company")  //创建节点
node.insertBefore(newNode,node.lastNode)       //插入节点
textNode = myDocument.creatTextNode("北大方正") //创建文本元素
node.childNodes.item(1).appendChild(textNode)  //添加子元素(值)


37、删除元素:
node = root.childNodes.item(0)                        //确定位置
oldNode = node.removeChild(node.childNodes.item(1))   //删除节点

其中,oldNode中存放的是已被删除的节点。在删除某个节点时,
以该节点为根的子树将整个被删除,因此得到的结果DOM树恢复原状。


38、修改元素:

假如想把张三的电子邮件地址更改为zhs@pku.edu.cn,通过下列语句就可以实现:

node = root.childNodes.item(0)                               //查找节点
emailNode = node.childNodes.item(0)                          //确定要修改元素位置
emailNode.childNodes.item(0).nodeValue = zhs@pku.edu.cn      //替换元素


39、SAX接口分析:
SAX的全称是Simple APIs for XML,也即XML简单应用程序接口。
与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式。
当使用SAX分析器对XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,
应用程序通过这些事件处理函数实现对XML文档的访问,因而SAX接口也被称作事件驱动接口。

      SAX是一种事件驱动的接口,它的基本原理是由接口的用户提供符合定义的处理器,
      XML分析时遇到特定的事件,就去调用处理器中特定事件的处理函数。一般SAX接口都是用JAVA实现的,
      但事实上C++也可以用于实现SAX接口,只是C++的分析器比较少。之所以叫做"简单"应用程序接口,
      是因为这个接口确实非常简单,绝大多数事情分析器都没有做,需要应用程序自己去实现,
      因而开发者的任务也相应重一些。


40、SAX分析器中的几个主要API接口作一简单的介绍。

SAXParserFactory
SAXParserFactory对象用来按照系统属性中的定义创建一个分析器的实例,接口是Javax.xml.parser. SAXParserFactory。

Parser
org.xml.sax.Parser接口定义了类似setDocumentHandler的方法来创建事件处理函数。
另外,该接口中还定义了parser(URL)方法来对XML文档进行实际的分析工作。

DocumentHandler
当分析器遇到XML文档中的标记时,就会激活该接口中的startDocument,endDocument,startElement以及endElement等方法。
另外,characters方法以及processingInstruction方法也是在DocumentHandler接口中实现的。
当分析器遇到元素内部的文本内容时就会激活characters方法,当分析器遇到处理指令时就会激活processingInstruction方法。

ErrorHandler
当分析器在分析过程中遇到不同的错误时,ErrorHandler接口中的error、fatalError或者warning方法就会被激活。

DTDHandler
当处理DTD中的定义时,就会调用该接口中的方法。

EntityResolver
当分析器要识别由URI定义的数据时,就会调用该接口中的resolveEntity方法。

一个典型的SAX应用程序至少要提供一个DocumentHandler接口。一个健壮的SAX应用程序还应该提供ErrorHandler接口。


--  作者:卷积内核
--  发布时间:3/15/2006 10:25:00 AM

--  
41、在关系数据库中,数据仅仅是数据,它不包含层次结构信息;
而面向对象数据库可以将数据视为对象,数据是作为一个整体,包含了属性和方法,并能体现数据间的继承关系。


42、一个基于XML的数据库系统应该具备以下特征:

1>能够根据文档类型定义(DTD或Schema)确定数据库的模式。
也就是说,能够按照DTD或Schema来定义数据库,而无须再进行数据库的设计,
能够按照DTD或Schema的层次结构来进行基于XML语法的定位和查询。通过元素名字和属性来查询和定位元素。
2>支持DOM和SAX,可以进行事件驱动的XML处理。
3>内置数据处理语言模块(XML语法分析器),能够进行XML文档数据的语法分析,同时对数据库中的元素进行直接的定位操作。
4>提供标准的XML查询语言。通过套用一定的样式模式,输出多种格式的XML文档。
5>能够处理大型数据集合,能够对置标文本的结构和内容进行索引。
6>提供开发工具包,支持DOM、SAX、Java、Script语言等。
7>提供一定的机制保证数据的一致性。如通过行级或页级共享锁、排他锁对数据加锁,满足用户对数据进行并发读写时数据的有效性。
8>支持OLAP和数据仓库等高级应用。


43、对数据库操作ASP和DTD(Schema)的具体实现:

ASP:

<% @language = "VBScript" %>
<% Response.ContentType = "text/xml" %>
<?xml version="1.0" encoding="GB2312" ?>
<%’动态构建XML文档
  set xmlDoc = Server.CreateObject(Microsoft.XMLDOM)
  set root = xmlDoc.createNode("element","联系人列表","")
  xmlDoc.appendChild(root)

  ’查询数据库
  sqlStr = "select * from clientList"
  set cConn = Server.CreateObject("ADODB.Connection")
  cConn.Open "CLIENTS","sa", ""
  set rsData = cConn.Execute(sqlStr)
  rsData.MoveFirst()

  while (not rsData.EOF )
    ’构建联系人子节点
    set tmpNode = xmlDoc.createNode("element","联系人","")
    xmlDoc.documentElement.appendChild(tmpNode)
    ’构建姓名、ID、公司、Email子节点
    for I = 0 to rsData.Fields.Count - 1
      set childNode = xmlDoc.createNode("element",rsData.Fields(i).Name,"")
      childNode.text = rsData.Fields(i)
      tmpNode.appendChild(childNode)
    next
   rsData.MoveNext()
  wend

  Response.Write(xmlDoc.xml)
%>


DTD:

<% Response.ContentType="text/xml" %>
<?xml version="1.0" encoding="GB2312" ?>
<联系人列表>

<% Set cConn = Server.CreateObject("ADODB.Connection")
   cConn.Open "CLIENTS","sa", ""
   Set rsData = cConn.Execute("select * from clientList")
   do while not rsData.Eof
%>
<联系人>
  <姓名><%=rsData("Name")%></姓名>
  <ID><%=rsData("ID")%></ID>
  <公司><%=rsData("Company")%></公司>
  <Email><%=rsData("Email")%></Email>
</联系人>
<% rsData.MoveNext
   Loop
   rsData.Close
   Set rsData = nothing
%>

</联系人列表>


最终生成XML文档为:

<?xml version = "1.0" encoding="GB2312" standalone = "no"?>

<联系人列表>
    <联系人>
        <姓名>张三</姓名>
        <ID>1</ID>
        <公司>A公司</公司>
        <EMAIL>zhang@aaa.com</EMAIL>
    </联系人>

    <联系人>
        <姓名>李四</姓名>
        <ID>2</ID>
        <公司>B公司</公司>
        <EMAIL>li@bbb.org</EMAIL>
    </联系人>
</联系人列表>


--  作者:卷积内核
--  发布时间:3/15/2006 10:25:00 AM

--  
44、这种方案存在一个前提,那就是,开发者必须了解文档结构,并且通过编程严格控制输出文档的格式。
但细心的读者可能会产生疑问:既然数据已经存储在数据库中,又何必大费周折重新定义一遍文档结构呢?
XML的自描述性何在?为了解决这个问题,微软将其ADO技术进行了扩展以提供对XML的更大支持,
结果是可以根据数据库表的内在结构直接输出XML文档,文档的格式将符合默认的DTD定义。下面是一个用Visual Basic 6.0编写的实例:

’声明连接和结果集
Dim cConn As ADODB.Connection
Dim rsData As ADODB.Recordset
Private Sub Form_Load()
  ’连接数据库
  Dim query As String
  Set cConn = New ADODB.Connection
  cConn.ConnectionString = "DSN=nwind;UID=sa;PWD=;"
  cConn.Open

  ’执行数据库查询
  query = "Select * FROM clientList"
  Set rsData = cConn.Execute(query)

  ’将数据库返回结果集保存至文件
  On Error Resume Next
    Kill ("recordset.xml")
  rsData.Save "output.xml", adPersistXML
End Sub

下面给出的是该程序执行后生成的XML文档--output.xml。通过分析,可以发现,
它实际上是一个内嵌XML Schema的XML实例文档。该实例文档的主元素是<rs:data>,
命名空间rs由xmlns:rs=’urn:schemas-microsoft-com:rowset’定义;
数据库查询返回的每一条记录都作为<rs:data>的一个子元素,用<z:row>表示。
<z:row>子元素实际上是空元素,信息均以属性的方式体现,属性来自于返回的数据库字段。
内嵌的Schema部分<s:Schema id=’RowsetSchema’>定义了元素<row>的组织结构和规则。

<xml xmlns:s=’uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882’
     xmlns:dt=’uuid:C2F41010-65B3-11d1-A29F-00AA00C14882’
     xmlns:rs=’urn:schemas-microsoft-com:rowset’
     xmlns:z=’#RowsetSchema’
>
<s:Schema id=’RowsetSchema’>
  <s:ElementType name=’row’ content=’eltOnly’>
    <s:attribute type=’Name’/>
    <s:attribute type=’ID’/>
    <s:attribute type=’Company’/>
    <s:attribute type=’Email’/>
    <s:extends type=’rs:rowbase’/>
  </s:ElementType>

  <s:AttributeType name=’Name’ rs:number=’1’ rs:nullable=’true’         rs:write=’true’>
    <s:datatype dt:type=’string’ dt:maxLength=’10’/>
  </s:AttributeType>

  <s:AttributeType name=’ID’ rs:number=’2’ rs:nullable=’true’ rs:write=’true’>
    <s:datatype dt:type=’int’/>
  </s:AttributeType>

  <s:AttributeType name=’Company’ rs:number=’3’ rs:nullable=’true’ rs:write=’true’>
    <s:datatype dt:type=’string’ dt:maxLength=’20’/>
  </s:AttributeType>

  <s:AttributeType name=’Email’ rs:number=’4’ rs:nullable=’true’ rs:write=’true’>
    <s:datatype dt:type=’string’ dt:maxLength=’20’/>
  </s:AttributeType>
</s:Schema>

<rs:data>
  <z:row Name=’张三’ ID=’1’ Company=’A公司’ Email=’zhang@aaa.com’/>
  <z:row Name=’李四’ ID=’2’ Company=’B公司’ Email=’li@bbb.org’/>
</rs:data>
</xml>

ADO提供了文档保存功能,通过它,ASP可以将数据库返回结果集保存至XML文件,
这些XML文件经由XSL样式化后可以在浏览器直接显示,也可以传输至其他应用系统供再次利用。
另外,值得一提的是,微软在其ADO2.5和IIS5.0中又增加了更高级的支持,即,可以将数据库
返回的结果直接转换为XML在浏览器中显示,而不必先保存至文件。下面的实例片段有力地说明了这一点:

<%
  Set rsData = Server.CreateObject("ADODB.Recordset")
  Response.ContentType="text/xml"
  rsData.Open "select * from clientList", "File Name=" & Server.MapPath("ado.udl")
  rsData.Save Response, adPersistXML
  rsData.Close
  Set cConn = nothing
%>

常用的XPath表达式

记号                      含义

a                     上下文节点的a元素
*                     上下文节点的所有元素
a/b                   以上下文节点的a元素为父节点的b元素
a//b                  以上下文节点的a元素为祖先的b元素
a|b                   上下文节点的a元素和b元素
a[表达式]              符合表达式的上下文节点的a元素
.                     上下文节点
..                    上下文节点的父节点
/                     根节点
@a                    上下文节点的a属性
@*                    上下文节点的所有属性
node()                所有节点
text()                文本节点


<ElementType>元素有五个重要属性(参见表7 - 6)。

XML 模式命令                                XML-DR命令
schema                                      Schema

element                                   ElementType  
element                                   Refelement
attribute                                 AttributeType
none                                      attribute
datatype                                  datatype
Nonede                                    scription
Model                                     Group, groupgroup


表7 - 6
ElementType属性                                        含义

name                                                 元素名称

content                                   描述可能包含在元素里的内容: empty,textOnly(只对PCDATA),
                                          eltOnly(只对元素内容),mixed(PCDATA和元素)

dt:type                                   表示元素类型。这个属性与XML 模式里的<datatype>元素一致。
                                          有效值从X M L数据类型预览工具得到model开放或关闭的内容模型

order                                     子元素的基本顺序: one(从一系列元素选出的一个)、seq(特定的元素
                                          序列)、many(以任意顺序可能出现或不出现的特定元素)
                                          元素还能包含下面四种内容类型之一,这些内容类
       型用< Element Type>元素的content属性来
描述:
. 没有内容: empty
. 只有文本: textOnly
. 只有子元素:eltOnly
. 混合文本和子元素: mixed
我们能用< element>和<attribute>元素去约束已经声明的元素的内容。这些元素声明子元素
和可以用于一个元素的属性。
<element>元素能有三个属性(参见表7 - 7)。


表7 - 7
<element>属性                                       描述

type                                与在模式里定义的<ElementType>的name属性值相一致

minOccurs                           引用元素类型在元素里能出现的最小次数,当出现次数为0,即元素是可
                                    选的,此值为0;当最少出现一次时,此值为1(缺省值为1)

maxOccurs                           引用元素类型在元素里能出现的最大次数,当出现次数最多为1次时,此
                                    值为1;当出现次数不限制时,此值为*(缺省值为1)

<attribute>元素也能有三个属性(参见表7 - 8)。

表7 - 8

<attribute>属性                                       描述

default                            属性的缺省值,不考虑它所重载的<Attribute>元素里提供的任何缺省值
type                               与在模式里定义的< AttributeType>元素的name属性值相一致
required                           指明属性是否必须出现在元素里,如果需要取值yes。如果在< AttributeType>
                                   元素里指明了就不需要了


<group>属性                                          含义

maxOccursgroup                       可能出现的最大次数。可取值0或*(很多)
minOccursgroup                       可能出现的最小次数。可取值0(可选)或1(至少出现1次)
order                                包含的元素和组的顺序。可能是one(从group里选出一个元素)、seq
                                     (序列里的每个元素)或many(group里可能或不可能,按一定顺序出现的
                                     任意元素)


--  作者:卷积内核
--  发布时间:3/15/2006 10:28:00 AM

--  
由于前段时间是边学边发,所以凌乱了一些,应广大兄弟姐妹建议今天整理一下,希望能多多交流,让我们论坛更强大。
--  作者:minmin0876
--  发布时间:4/9/2007 8:00:00 PM

--  
替你顶起来  哈哈

好东西哦
怎么能沉了呢


--  作者:klzhuang
--  发布时间:11/29/2007 10:44:00 AM

--  
ding~~~
还是刚刚接触这个东西!迷茫ing
--  作者:mike_fang
--  发布时间:5/26/2008 5:14:00 PM

--  
初学,了解
W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
5,718.750ms