xml全称为Extensible Markup Language,可扩展标记语言;是由W3C组织发布的,目前遵循的是W3C组织于2000年发布的xml.0规范。
1969年gml(通用标记语言)主要目的是在不同的机器上进行通信的数据规范
1985年sgml(标准通用标记语言)
1993年html(www网)
Html语言本身是是由一些缺陷的,比如
(1)标记不能自定义
<html> <body> <table> <td>123</td> </table> </body> </html>
|
(2)html本身缺少一些含义
<html> <body> <h1>水浒英雄</h1> <table> <tr> <td>宋江</td> </tr> </table> </body> </html> |
(3)html本身没有真正的国际化
(1)xml的出现解决了程序间数据传输的问题;
比如QQ之间的数据用xml格式来传递,具有良好的可读性和可维护性;
(2)可以用做配置文件;
(3)可以充当小型的数据库;
因为直接读取文件显然要比读取数据库更快。
入门案例:使用xml来记录一个班级的信息
<?xml version="1.0" encoding="gb2312"?> <class> <stu id="001"> <name>杨过</name> <sex>男</sex> <age>30</age> </stu> <stu id="002"> <name>小龙女</name> <sex>女</sex> <age>30</age> </stu> </class> |
一个xml文件分为如下几个部分内容:
<?xml version="1.0" encoding="gb2312"?> |
a、xml声明放在xml文档的第一行;
b、xml声明由以下几个部分组成:
version——文档符合xml1.0规范
encoding——文档字符编码,比如“utf-8”,“gb2312”;
standalone——文档定义是否独立使用,默认是“no”;
a、每个xml文档必须有且仅有一个根元素;
b、根元素是一个完全包括文档中其他所有元素的元素;
c、根元素的起始标记要放在所有其他元素的起始标记之前;
d、根元素的结束标记要放在所有其他元素的结束标记之后;
e、xml元素指xml文件中出现的标签,一个标签分为开始标签和结束标签,主要有以下两种标签格式:
包含标签体:<a>www</a>
不包含标签体:<a></a>,简写为</a>
f、一个标签中可以嵌套若干个子标签,但所有标签必须是合理的嵌套,决不允许交、叉嵌套;
g、对于xml标签中出现的所有空格和换行,xml解析程序都会当做标签内容进行处理,因此在编写xml文件时要特别注意空格和换行;
h、一个xml元素可以包含字母、数字以及其它一些可见字符,但必须遵守下面的一些规范:
l 区分大小写,例如,<P>和<p>是两个不同的标记;
l 不能艺术字或“_”(下划线)开头;
l 不能包含空格;
l 名称中间不能包含冒号(:)。
a、属性值用双引号或单引号分隔;
b、一个元素可以有多个属性,它的基本格式为:<元素名属性名=”属性值”>;
c、特定的属性名称在同一个元素标记中只能出现一次;
d、属性值不能包括<,>,&.
a、注释内容中不要出现--;
b、不要把注释放在标记中间;
c、注释不能嵌套;
d、可以在除标记以外的任何地方放注释;
e、注释采用:“<!—注释-->”格式;
注意:xml声明之前不能有注释。
a、有些内容可能不想让解析引擎解析执行,而是当做原始内容来处理,用于把整段文本解释为纯字符数据而不是标记的情况。CDATA节中的所有字符都会被当做元素字符数据的常量部分,而不是xml标记。
b、语法形式:
<![CDATA[。。。。。]]>
c、可以输入任意字符,当然是除]]>之外了;
d、不可以嵌套使用。
e、转义字符
对于一些单个字符,若执行显示其原始样式,也可以使用转义的形式予以处理
转义符 |
符号 |
< |
< |
> |
> |
& |
& |
" |
“ |
' |
‘ |
a、处理指令,简称PI,处理指令用来指挥解析引擎如何解析xml文档内容;
b、在xml文档中使用xml-stylesheet指令,通知xml解析引擎,应用css文件显示xml文档内容,格式如下:
<?xml-stylesheet type="text/css" href="。。.css"?> |
在myClass.xml文件中引入my.css样式:
name{ font-size:100px; font-weight:bold; color:red; } age{ font-size:50px; font-weight:bold; color:blue; } sex{ font-size:20px; font-weight:bold; color:yellow; } |
修改后的myClass.xml代码如下:
<?xml version="1.0" encoding="utf-8"?> <?xml-stylesheet type="text/css" href="my.css"?> <class> <stu id="001"> <name>杨过</name> <sex>男</sex> <age>30</age> </stu> <stu id="002"> <name>小龙女</name> <sex>女</sex> <age>30</age> </stu> </class> |
注意:编码问题
ansi编码:美国国家标准协会制定的编码格式标准,在不同的国家是不一样的,比如在中国是gb2312。
总结:
遵循如下规则的xml文档称为正规的xml文档:
l 语法规范
a、包含xml声明语句;
b、必须有且仅有一个根元素;
c、标记大小写敏感;
d、属性值用引号;
e、标记成对且空标记关闭;
f、元素正确嵌套。
l 元素语法
a、名称中可以包含字母、数字或者其它字符;
b、名称中不能包含空格;
c、名称中不能含有冒号(注:冒号留给命名空间使用)。
xml约束是指通过编写一个文档来约束一个xml文档的书写规范,常用的约束技术是XML DTD和XML Schema。
DTD(Document Type Defintion),全称为文档类型定义。
a、xml与DTD之间的关系如下图所示:
b、基本语法:
<!ELEMENT 元素名类型> |
c、快速入门案例:
编写myClass2.xml文件和myClass2.dtd文件,代码如下所示:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE 班级 SYSTEM "myClass2.dtd"> <班级> <学生> <姓名>周星驰</姓名> <年龄>23</年龄> <介绍>学习刻苦</介绍> </学生> <学生> <姓名>林青霞</姓名> <年龄>45</年龄> <介绍>认真</介绍> </学生> </班级> |
<!ELEMENT 班级 (学生+)> <!ELEMENT 学生 (姓名,年龄,介绍)> <!ELEMENT 姓名 (#PCDATA)> <!ELEMENT 年龄 (#PCDATA)> <!ELEMENT 介绍 (#PCDATA)> |
编写校验xml文档正确项的解析工具,在IE5以上浏览器内置了xml解析工具,也可通过xmlspy工具进行验证;
主要步骤如下:
1、创建xml文档解析器对象 2、开启xml校验 3、装载xml文档 4、获取错误信息 |
实现代码如下所示:
<html> <head> <title>my xml verfiy tool</title> <script language="javascript"> <!-- var xmldoc = new ActiveXObject("Microsoft XMLDOM"); xmldoc.validateOnParse ="true";//开启校验 xmldoc.load("myClass2.xml");//指定校验哪个xml文件 document.writeln("错误信息是:"+xmldoc.parseError.Error); document.writeln("错误信息所在行:"+xmldoc.parseError.line); --> </script> </head> </html> |
d、DTD文档的声明以及引用
内部DTD文档
<!DOCTYPE 根元素 [定义内容]> |
示例:
<?xml version="1.0" encoding="gb2312"?> <!DOCTYPE poem[ <!DOCTYPE poem (author,title,content)> <!ELEMENT author (#PCDATA)> <!ELEMENT title (#PCDATA)> <!ELEMENT content (#PCDATA)> ]> <poem> <author>王维</author> <title>鹿柴</title> <content>空山不见人,但闻人语声。 返景入深林,复照青苔上。 </content> </poem> |
注意:例中的定义关键字一定要大写,比如DOCTYPE,ELEMENT,#PCDATA,且元素名称与数据类型之间也要有空格。
外部DTD文档
<!DOCTYPE 根元素 SYSTEM “DTD文件路径”> |
示例见入门案例。
内外部DTD文档结合
<!DOCTYPE 根元素 SYSTEM “DTD文件路径”[定义内容]> |
xml文件使用DOCTYPE声明语句来指明它所遵循的DTD文件,DOCTYPE声明语句有两种形式:
l 当引用的文件在本地时,采用如下方式:
<!DOCTYPE 文档根结点 SYSTEM “DTD文件的URL”> |
l 当引用的文件时一个公共的文件时,采用如下形式:
<!DOCTYPE 文档根结点 PUBLIC “DTD名称” “DTD文件的URL”> |
示例:
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> |
e、DTD元素
l 语法
<!ELEMENT NAME CONTENT> |
以上三个单词分别对应关键字、元素名称、元素类型(大写);
CONTENT包括以下三种:
1)EMPTY:该元素不能包含子元素和文本,但是可以有属性(即空元素);
示例:
<!ELEMENT 人 EMPTY> <家庭> <人名字="皮诺曹"性别="男"年龄="6"/> </家庭> |
2)ANY:该元素可以包含任何在DTD中定义的元素内容;
示例:
<!ELEMENT 人 ANY> <家庭> <人>皮诺曹</人> <人><大人>皮诺曹爸爸</大人></人> </家庭> |
3)#PCDATA:可以包含任何字符数据,但是不能再其中包含任何子元素其它类型(组合)。
<!ELEMENT 人 (#PCDATA)> <家庭> <人性别="男"年龄="6">皮诺曹</人> </家庭> |
组合类型如下所示:
<!ELEMENT 家庭 (人+,家电*)> <家庭> <人名字="郭大路"性别="男"年龄="25"/> <人名字="李寻欢"性别="男"年龄="38"爱好="作个教育家和伟人"/> <家电名称="彩电"数量="3"/> </家庭> |
修饰符如下所示:
编号 |
符号 |
用途 |
示例 |
示例说明 |
1 |
( ) |
用来给元素分组 |
(古龙|金庸),(王朔|余杰),三毛 |
分成三组 |
2 |
| |
在列中的对象中选择一个 |
(男人|女人) |
表示男人或者女人必须出现,两者至少选一 |
3 |
+ |
该对象最少出现一次,可以出现多次 |
(成员+) |
表示成员必须出现,而且可以出现多个成员 |
4 |
* |
该对象允许出现零次到人一多次 |
(爱好*) |
爱好可以出现零次到多次 |
5 |
? |
该对象可以出现,但是只能出现一次(0到1次) |
(菜鸟?) |
菜鸟可以出现,也可以不出现,但是如果出现的话,最多只能出现一次 |
6 |
, |
对象必须按指定的顺序出现 |
(西瓜,苹果,香蕉) |
表示西瓜,苹果,香蕉必须出现,并且按这个顺序出现 |
a、语法:
<!ATTLIST 元素名称 属性名称类型属性特点 属性名称类型属性特点... > |
其中类型包括四种:CDATA、ID、IDREF/IDREFS、Enumerated、ENTITY/ENTITIES;
属性特点包括四种:#REQUIRED、#IMPLIED、#FIXED value、#Default value。
b、属性类型:
l CDATA:属性值可以使任何字符(包括数字和中文)
<!ATTLIST 木偶 姓名 CDATA #REQUIRED > <木偶姓名="dirk"> <木偶姓名="德克"> <木偶姓名="dirk41"> |
l ID:表明该属性的取值必须是唯一的。
<!ELEMENT 公司职员 ANY> <!ATTLIST 公司职员 编号 ID #REQUIRED 姓名 CDATA #REQUIRED > <公司职员编号="1001"姓名="张三"> <公司职员编号="1002"姓名="李四"> |
l IDREF/IDREFS:IDREF属性的值指向文档中其它地方声明的ID类型的值;
IDREFS同IDREF,但是可以具有由空格分开的多个引用。
<!ELEMENT 家庭(人+)> <!ELEMENT 人 EMPTY> <!ATTLIST 人 relID ID #REQUIRED parentID IDREFS #IMPLIED name CDATA #REUIRED > <家庭> <人 relID="p01" name="爸爸"> <人 relID="p02" name="妈妈"> <人 relID="p03" parentID="p01 02" name="儿子"> </家庭> |
l Enumerated:事先定义好一些值,属性的值必须在所列出的值的范围内。
<!ATTLIST person 婚姻状态(single|married|divorced|widowed) #IMPLIED> <!ATTLIST person 性别(男|女) #REQUIRED> |
c、属性的特点:
l #REQUIRED:元素的所有实例都必须有该属性的值(NOT NULL)。
语法:
<!ATTLIST 元素名属性名属性类型 #REQUIRED> |
示例:
<!ATTLIST person number CDATA #REQUIRED> <person number="5678"/> |
l #IMPLIED:元素的实例中可以忽略该属性(NULL)。
语法:
<!ATTLIST 元素名属性名属性类型 #IMPLIED> |
示例:
<!ATTLIST contact fax CDATA #IMPLIED> <contact fax="555-667788"> |
l #FIXED value:元素实例中该属性的值必须为指定的固定值。
语法:
<!ATTLIST 元素名属性名属性类型 #FIXED "value"> |
示例:
<!ATTLIST sender company CDATA #FIXED "Microsoft"> <sender company="Microsofr"/> |
l Default value:为属性听过一个默认的值。
语法:
<!ATTLIST 元素名属性名类型 "value"> |
示例:
<!ATTLIST payment type CDATA "check"> <payment type="check"/> |
d、实体:
l 定义:是用于为一段内容创建一个别名,以后再xml文档中就可以使用别名引用这段内容了,在DTD定义中,一条<!ENTITY ...>语句用于定义一个实体;实体可以分为两种类型:引用类型和参数实体。
l 引用实体:主要在xml文档中被应用;
语法:
<!ENTITY 实体名称 "实体内容">:直接转变成实体内容 |
引用方式:
&实体名称; |
示例:
<!ENTITY copyright "I am a coder"> ©right; |
l 参数实体:被DTD文档自身使用;
语法:
<!ENTITY %实体名称 "实体内容"> |
引用方式:
%实体名称; |
示例:
<!ENTITY % TAG_NAMES "姓名|EMAIL|电话|地址"> <!ENTITY 个人信息 (%TAG_NAME;|生日)> <!ENTITY 客户信息 (%TAG_NAME;|公司名)> |
<!ENTITY %common.attributes id ID #IMPLIED account CDATA #REQUIRED > ... <!ATTLIST purchaseOrder %common.attributes;> <!ATTLIST item %commo.attributes;> |
e、练习:
根据以下的dtd文件写出相对应的xml文件:
1)报纸文章 DTD
!DOCTYPE NEWSPAPER [ <!ELEMENT NEWSPAPER (ARTICLE+)> <!ELEMENT ARTICLE (HEADLINE,BYLINE,LEAD,BODY,NOTES)> <!ELEMENT HEADLINE (#PCDATA)> <!ELEMENT BYLINE (#PCDATA)> <!ELEMENT LEAD (#PCDATA)> <!ELEMENT BODY (#PCDATA)> <!ELEMENT NOTES (#PCDATA)> <!ATTLIST ARTICLE AUTHOR CDATA #REQUIRED> <!ATTLIST ARTICLE EDITOR CDATA #IMPLIED> <!ATTLIST ARTICLE DATE CDATA #IMPLIED> <!ATTLIST ARTICLE EDITION CDATA #IMPLIED> <!ENTITY NEWSPAPER "Vervet Logic Times"> <!ENTITY PUBLISHER "Vervet Logic Press"> <!ENTITY COPYRIGHT "Copyright 1998 Vervet Logic Press"> ]> |
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE NEWSPAPER SYSTEM "newspaper.dtd"> <NEWSPAPER> <ARTICLE AUTHOR="steven" EDITOR="dirk" DATE="2012" EDITION="china"> <HEADLINE>let us go mavs</HEADLINE> <BYLINE>let us go dirk</BYLINE> <LEAD>Mavs</LEAD> <BODY>huangwenbo</BODY> <NOTES>sanjiangunivesity</NOTES> </ARTICLE> </NEWSPAPER> |
2)产品目录 DTD
<!DOCTYPE CATALOG [ <!ENTITY AUTHOR "John Doe"> <!ENTITY COMPANY "JD Power Tools, Inc."> <!ENTITY EMAIL "[email protected]"> <!ELEMENT CATALOG (PRODUCT+)> <!ELEMENT PRODUCT (SPECIFICATIONS+,OPTIONS?,PRICE+,NOTES?)> <!ATTLIST PRODUCT NAME CDATA #IMPLIED CATEGORY (HandTool|Table|Shop-Professional) "HandTool" PARTNUM CDATA #IMPLIED PLANT (Pittsburgh|Milwaukee|Chicago) "Chicago" INVENTORY (InStock|Backordered|Discontinued) "InStock"> <!ELEMENT SPECIFICATIONS (#PCDATA)> <!ATTLIST SPECIFICATIONS WEIGHT CDATA #IMPLIED POWER CDATA #IMPLIED> <!ELEMENT OPTIONS (#PCDATA)> <!ATTLIST OPTIONS FINISH (Metal|Polished|Matte) "Matte" ADAPTER (Included|Optional|NotApplicable) "Included" CASE (HardShell|Soft|NotApplicable) "HardShell"> <!ELEMENT PRICE (#PCDATA)> <!ATTLIST PRICE MSRP CDATA #IMPLIED WHOLESALE CDATA #IMPLIED STREET CDATA #IMPLIED SHIPPING CDATA #IMPLIED> <!ELEMENT NOTES (#PCDATA)> ]> |
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE CATALOG SYSTEM "product.dtd"> <CATALOG> <PRODUCT NAME="lenovo" CATEGORY="HandTool" PARTNUM="abc" PLANT="Chicago" INVENTORY="InStock"> <SPECIFICATIONS WEIGHT="800" POWER="600">lenove y460p</SPECIFICATIONS> <OPTIONS FINISH="Matte" ADAPTER="Included" CASE="HardShell">123</OPTIONS> <PRICE>100</PRICE> </PRODUCT> </CATALOG> |
l xml Schema也是一种用于定义和描述XML文档结构与内容的模式语言,其出现是为了克服DTD的局限性。
l xml Schema的特点:
a、xml Schema比dtd更加符合XML语法结构,因为xml Schema自身就是xml文件,为了有所区别,扩展名通常为.xsd;
b、xml解析器很容易解析出xml Schema文档中的内容;
c、xml Schema比XML DTD支持更多的数据类型,并支持用户自定义新的数据类型;
d、xml Schema对名称空间支持的非常好;
e、xml Schema定义约束的能力非常强大,可以对XML实例文档作出细致的语义限制。
l 一个XML Schema文档通常称之为模式文档(约束文档),遵循这个文档书写的xml文件称之为实例文档。
l 和xml文件一样,一个xml Schema文档也必须有一个根结点,但这个根结点的名称为Schema。
l 编写一个xml Schema岳苏文档后,通常需要把这个文件中的声明的元素绑定到一个uri地址上,在xml Schema技术中有一个专业术语来描述这个过程,即把XML Schema文档声明的元素绑定到一个名称空间上,以后xml文件就可以通过这个URI(即名称空间)来告诉解析引擎,xml文档正编写的元素来自哪里,被谁约束。
关于名称空间的注意点:
l 为什么要声明名称空间:由于xml文档可以被任何组织或个人定义,这就完全有可能在一个xml文件中出现重复的元素,此时使用名称空间可以加以区分。
l 在xml Schema中,每个模式文档都可以被赋以一个唯一的名称空间,名称空间用一个唯一的URI(Uniform Resource Identifier,统一资源标示符)表示。
比如:xml文件中的内容:
<itcast:书架 xmlns:itcast="http://www.itcast.cn"> <itcast:书>....</itcast:书> </itcast> |
此处使用itcast来指向声明的名称,以便于后面对名称空间的引用。
l 名称空间中的uri虽然是以http://开头,但是它可以不指向任何一个真实的地址,而仅仅是作为一个名称空间来声明。
快速入门案例:
编写book.xsd文件来约束book.xml文件,代码如下所示:
<?xml version="1.0" encoding="UTF-8" ?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://wwwtcast.cn" elementFormDefault="qualified"> <xs:element name='书架' > <xs:complexType> <xs:sequence maxOccurs='unbounded' > <xs:element name='书' > <xs:complexType> <xs:sequence> <xs:element name='书名' type='xs:string' /> <xs:element name='作者' type='xs:string' /> <xs:element name='售价' type='xs:string' /> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> |
<?xml version="1.0" encoding="UTF-8"?> <itcast:书架 xmlns:itcast="http://www.itcast.cn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.itcast.cn book.xsd"> <itcast:书> <itcast:书名> Javascript网页开发 </itcast:书名> <itcast:作者> 张孝祥 </itcast:作者> <itcast:售价> 28.00元 </itcast:售价> </itcast:书> </itcast:书架> |
使用默认名称空间
l 基本格式:
xmlns=”URI” |
l 举例:
<?xml version="1.0" encoding="utf-8"?> <书架 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xmlbook.xsd"> <书> <书名> Javascript网页开发 </书名> <作者> 张孝祥 </作者> <售价> 28.00元 </售价> </书> </书架> |
5.1.1、xml解析分为:dom解析和sax解析
dom:Document Object Model,即文档对象模型,是W3C组织推荐的处理xml的一种方式;
sax:Simple API for xml,不是官方标准,但它是xml社区事实上的标准,几乎所有的xml解析器都支持它。
5.1.2、JAXP介绍
l JAXP开发包是J2SE的一部分,它由javax.xml、org.w3c.dom、org.xml.sax包及其子包组成;
l 在javax.xml.parsers包中,定义了几个工厂类,程序员调用这些工厂类就可以得到对xml文档进行接卸的DOM和SAX的解析器对象。
5.1.3、获得JAXP中的DOM解析器的步骤
l 1、调用DocumentBuilderFactory.newInstance()方法得到创建DOM解析器的工厂。
l 2、调用工厂对象的new DocumentBuilder方法得到DOM解析器对象。
l 3、调用DOM解析器对象的parse()方法解析xml文档,得到代表整个文档的Document对象,进行可以利用DOM特性对整个xml文档进行操作了。
l DOM 模型就是Document Object Model;
l DOM 解析器在解析XML文档给时,会把文档的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点);
l 在DOM中,节点之间关系如下所示:
(1)位于一个节点之上的节点是该节点的父节点(parent);
(2)一个节点之下的节点是该节点的子节点(children);
(3)同一层次,具有相同父节点的节点是兄弟节点(sibling);
(4)一个节点的下一个层次的节点是兄弟节点(descendant);
(5)父、祖父节点及所有位于节点上面的,都是节点的祖先(ancestor)。
xml DOM的解析图如下所示:
5.2.1、Node对象
l Node对象提供了一系列常量来代表节点的类型,当开发人员获得某个Node类型后,就可以把Node节点转换成相应的节点对象(Node的子类对象),以便调用其特有的方法,
l Node对象提供了相应的方法去获得它的父节点或自己点。
5.2.2、更新XML文档
l javax.xml.transform包中的Transformer类用于把代表xml文件的Document对象转换成某个格式后进行输出,例如把xml文件应用样式表后转换成一个html文档。利用这个对象,也可以把Document对象用重新写入到一个xml文件中;
l Transformer类通过transform方法完成转换操作,该方法接收一个源和一个目的地;
l Transformer对象通过TransformerFactory获得。
5.2.3、JAXP实例:
对class.xml文件进行CRUD操作,class.xml中代码如下所示:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <班级> <学生> <姓名>周星驰</姓名> <年龄>23</年龄> <介绍>学习刻苦</介绍> </学生> <学生 > <姓名>林青霞</姓名> <年龄>45</年龄> <介绍>认真</介绍> </学生> </班级> |
DomXml1.java代码如下所示:
package com.hwb;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList;
public class DomXml1 { public static void main(String[] args) throws Exception { // 利用dom技术对xml文件进行CRUD操作 // 创建一个DocumentBuilderFactory DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); // 通过DocumentBuilderFactory得到一个DocumentBuilder对象 DocumentBuilder dBuilder = dbf.newDocumentBuilder(); // 指定解析xml文件的地址 Document document = dBuilder.parse("src/class.xml"); // 遍历xml文件 list(document); // 查询某个学生的信息(假设取出第一个学生的信息) read(document); // 添加一个学生到xml文件中 add(document); // 从xml文件中删除一个学生信息 delete(document); // 更改xml文件中某个学生的信息 update(document); }
public static void update(Document document) throws Exception { // 首先找到需要更改的节点并作出修改 Element node = (Element) document.getElementsByTagName("学生").item(0); Element node_name = (Element) document.getElementsByTagName("姓名").item( 0); node_name.setTextContent("宋江"); // 更新xml文件 // 得到TransformerFactory TransformerFactory tff = TransformerFactory.newInstance(); // 通过TransformerFactory得到一个转换器 Transformer tf = tff.newTransformer(); tf .transform(new DOMSource(document), new StreamResult( "src/class.xml"));
}
public static void delete(Document document) throws Exception { // 删除属性sex Element node = (Element) document.getElementsByTagName("学生").item(0); node.removeAttribute("sex"); // 更新xml文件 // 得到TransformerFactory TransformerFactory tff = TransformerFactory.newInstance(); // 通过TransformerFactory得到一个转换器 Transformer tf = tff.newTransformer(); tf .transform(new DOMSource(document), new StreamResult( "src/class.xml")); }
public static void add(Document document) throws Exception { // 创建一个新的学生的节点 Element newStu = document.createElement("学生"); // 为学生添加属性 newStu.setAttribute("sex", "男"); // 继续向下创建三个节点,包括姓名、年龄、介绍 Element newStu_name = document.createElement("姓名"); // 为该节点赋值 newStu_name.setTextContent("小明"); Element newStu_age = document.createElement("年龄"); // 为该节点赋值 newStu_age.setTextContent("23"); Element newStu_introduce = document.createElement("介绍"); // 为该节点赋值 newStu_introduce.setTextContent("学习认真"); // 将学生节点与姓名、年龄、介绍三个节点相关联 newStu.appendChild(newStu_name); newStu.appendChild(newStu_age); newStu.appendChild(newStu_introduce); // 把新的学生节点添加到根元素 document.getDocumentElement().appendChild(newStu); // 得到TransformerFactory TransformerFactory tff = TransformerFactory.newInstance(); // 通过TransformerFactory得到一个转换器 Transformer tf = tff.newTransformer(); tf .transform(new DOMSource(document), new StreamResult( "src/class.xml")); }
public static void read(Document document) { // 通过getElementsByTagName()方法得出节点的名称 NodeList nl = document.getElementsByTagName("学生"); // 取出第一个学生的信息 Element stu = (Element) nl.item(0); String stu_sex = stu.getAttribute("sex"); System.out.println("学生的性别是" + stu_sex); Element name = (Element) stu.getElementsByTagName("姓名").item(0); System.out.println(name.getTextContent()); }
public static void list(Node node) { if (node.getNodeType() == node.ELEMENT_NODE) { System.out.println("名字是" + node.getNodeName()); } // 取出node的子节点 NodeList nodelist = node.getChildNodes(); // 通过递归调用来遍历xml文件 for (int i = 0; i < nodelist.getLength(); i++) { Node n = nodelist.item(i); list(n); } } } |
5.2.4、JAXP练习:
通过dom解析学生成绩,实现学生成绩管理系统。代码如下所示:
student.xml
<?xml version="1.0" encoding="UTF-8"?> <students> <student sid="001"> <name>小明</name> <course> <java>90</java> <oracle>90</oracle> <vb>89</vb> </course> </student> <student sid="002"> <name>小李</name> <course> <java>9</java> <oracle>70</oracle> <vb>8</vb> </course> </student> <student sid="003"> <name>小韩</name> <course> <java>90</java> <oracle>70</oracle> <vb>85</vb> </course> </student> <student sid="004"> <name>小明名</name> <course> <java>34</java> <oracle>50</oracle> <vb>58</vb> </course> </student> <student sid="005"> <name>小红</name> <course> <java>29</java> <oracle>39</oracle> <vb>88</vb> </course> </student> </students> |
StudentGrade.java
package com.dom.exercise;
import java.util.Scanner;
public class StudentGrade { public static void main(String[] args) throws Exception { while (true) { show(); } } public static void show() throws Exception { // 显示操作界面 System.out.println("查询所有学生的成绩----view"); System.out.println("退出系统----exit"); // 获取用户的操作类型 Scanner scanner = new Scanner(System.in); StudentService studentService = new StudentService(); String operType = scanner.next(); if (operType.equals("view")) { // view操作 System.out.println("所有学生的成绩如下所示:"); studentService.viewStudent(); } else if (operType.equals("exit")) { // exit操作 System.exit(1); } } } |
Student.java
package com.dom.exercise;
class Student { private String sid; //学生编号 private String name; //学生姓名 private int myjava; //Java成绩 private int myoracle;//Oracle成绩 private int myvb;//VB成绩 /*getter and setter*/ public String getSid() { return sid; }
public void setSid(String sid) { this.sid = sid; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getMyjava() { return myjava; }
public void setMyjava(int myjava) { this.myjava = myjava; }
public int getMyoracle() { return myoracle; }
public void setMyoracle(int myoracle) { this.myoracle = myoracle; }
public int getMyvb() { return myvb; }
public void setMyvb(int myvb) { this.myvb = myvb; } } |
StudentService.java
package com.dom.exercise; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; class StudentService { // 从指定的xml文件中得到信息 public Document getDocument(String FullFilePath) throws Exception { // 1、得到DocumentBuilderFactory DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory .newInstance(); // 2、得到DocumentBuilder DocumentBuilder documentBuilder = documentBuilderFactory .newDocumentBuilder(); // 3、指定得到的文件 return documentBuilder.parse(FullFilePath); } // 得到第一个元素的值 public String getFirstElementTextVal(Element element, String name) { return ((Element) element.getElementsByTagName(name).item(0)) .getTextContent() + "\t\t"; } // 显示所有学生的成绩 public void viewStudent() throws Exception { // 1、通过调用getDocument()方法显示学生信息 NodeList nodeList = getDocument("src/com/dom/exercise/student.xml") .getElementsByTagName("student"); // 2、通过遍历nodeList格式化显示学生成绩 for (int i = 0; i < nodeList.getLength(); i++) { Element element = (Element) nodeList.item(i); System.out.println("编号:" + element.getAttribute("sid") + "\t" + "名字:" + getFirstElementTextVal(element, "name") + "\t" + "Java成绩:" + getFirstElementTextVal(element, "java") + "\t" + "Oracle成绩:" + getFirstElementTextVal(element, "oracle") + "\t" + "VB成绩:" + getFirstElementTextVal(element, "vb") + "\t"); } } } |
5.3.1、概述:
l 在使用DOM解析xml文档时,需要读取整个xml文档,在内存中构建代表整个DOM树的Document对象,从而在对xml文档进行操作。此种情况下,如果xml文档特别大,就会消耗计算机的大量内存,严重的情况下可能会导致内存溢出。
l sax解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才对文档进行操作。
l 面试题:
阅读以下代码,请问该段代码是否正确?
package com.hwb; public class Test { public static void main(String[] args) { byte bytes[]=new byte[1024*1024*200]; bytes[0]=0; System.out.println(bytes[0]); } } |
运行结果会出现如下错误:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at com.hwb.Test.main(Test.java:4) |
默认情况下JVM的虚拟内存是64M,可以在“Properties for Xxx.java”中选择“Edit”按钮后选择“Argument”中“VM arguments”下添加“-Xmx200M”(200可以替换),即可指定jvm机启动的内存大小。
5.3.2、原理图:
|
5.3.3、sax解析机制
sax是一种推式机制,当创建一个sax解析器时解析器在发现xml文档中的内容是会把事件退给你,如何处理这些内容,由程序员自己决定。
在基于sax的程序中,有五个最常用的sax事件:
(1)startDocument()---->告诉我们解析器发现了文档的开始,并且解析器开始扫描文档;
(2)endDocument()--->告诉我们解析器发现了文档尾;
(3)startElement()--->告诉我们解析器发现了一个起始标签,该事件告诉我们元素的名称以及该元素所有的属性名和值;
(4)character()--->告诉我们解析器发现了一些文本,将得到一个字符数组,该数组的偏移量和一个长度变量,有这三个变量便可以得到解析器所发现的文本;
(5)endElement()--->告诉我们解析器发现了一个结束标签,该事件告诉元素的名称。
5.3.4、sax解析
sax采用事件处理的方式解析xml文件,利用sax解析xml文档,涉及两个部分:解析器和事件处理器:
l 解析器可以使用jaxp的API创建,创建出sax解析器后就可以指定解析器去解析某个xml文档了;
l 解析器采用sax方式在解析某个xml文档时,它只要解析到xml文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器;
l 事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松的得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。
5.3.5、sax方式解析xml文档
l 使用SAXParseFactory创建sax解析工厂
SAXParseFactory spf = SAXParseFactory.newInstance();
l 通过sax解析工厂得到解析器对象
SAXParse sp = spf.newSAXParse();
l 将解析对象和事件处理器对象关联
sp.parse(“src/myClass.xml”,new MyHander());
5.3.6、sax实例
myClass.xml文件代码如下所示:
<?xml version="1.0" encoding ="utf-8"?> <班级> <学生> <名字>周星驰</名字> <年龄>23</年龄> <介绍>学习刻苦</介绍> </学生> <学生> <名字>林青霞</名字> <年龄>32</年龄> <介绍>是一个好学生</介绍> </学生> </班级> |
SaxXml类代码如下所示:
package com.hwb;
import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory;
public class SaxXml { public static void main(String[] args) throws Exception { // 利用sax技术来解析xml文档,此例中解析myClass.xml文件 // 使用SAXParseFactory创建sax解析工厂 SAXParserFactory spf = SAXParserFactory.newInstance(); // 通过sax解析工厂得到解析器对象 SAXParser sp = spf.newSAXParser(); // 将解析对象和事件处理器对象关联 sp.parse("src/class.xml", new MyHander()); System.out.println("*****************"); sp.parse("src/class.xml", new Hander()); } } |
MyHander类代码如下所示:
package com.hwb;
import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler;
//定义事件处理类 class MyHander extends DefaultHandler { @Override //发现文档开始 public void startDocument() throws SAXException { System.out.println("startDocument"); }
@Override //发现xml文件中的一个元素 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { System.out.println("元素名称:" + qName); }
@Override //发现xml文件中的一个文本 public void characters(char[] ch, int start, int length) throws SAXException { String con = new String(ch,start,length); if(!con.trim().equals("")){ System.out.println(con); } }
@Override public void endElement(String uri, String localName, String qName) throws SAXException { // TODO Auto-generated method stub super.endElement(uri, localName, qName); }
@Override //发现文档结束 public void endDocument() throws SAXException { System.out.println("endDocument"); }
} |
Hander类代码如下所示:
package com.hwb;
import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; //只显示学生的姓名和年龄 class Hander extends DefaultHandler { private boolean isName = false; private boolean isAge = false; @Override //发现文档开始 public void startDocument() throws SAXException { System.out.println("startDocument"); }
@Override //发现xml文件中的一个元素 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { System.out.println("元素名称:" + qName); }
@Override //发现xml文件中的一个文本 public void characters(char[] ch, int start, int length) throws SAXException { String con = new String(ch,start,length); if(!con.trim().equals("")&&(isAge||isName)){ System.out.println(con); } isName =false; isAge = false;
}
@Override public void endElement(String uri, String localName, String qName) throws SAXException { if(qName.equals("名字")){ this.isName = true; }else if(qName.equals("年龄")){ this.isAge = true; } }
@Override //发现文档结束 public void endDocument() throws SAXException {
System.out.println("endDocument"); }
} |
5.4.1、DOM4J解析XML文档
l Dom4j是一个简单、灵活的开放源代码的库;与JDOM不同的是,dom4j使用接口和抽象基类,虽然dom4j的API相对复杂一些,但它提供了比JDOM更好的灵活性;
l Dom4j是一个非常优秀的Java xml API,具有性能优异、功能强大和极易使用的特点;现在很多软件采用的是Dom4j,比如说Hibernate。
l 使用Dom4j开发,需要先下载dom4j相应的jar文件。
5.4.2、Document对象
l Dom4j中,获得Document对象的方式有三种:
(1)读取xml文件,获得document对象
SAXReader saxReader = new SAXReader(); Docuement document = saxReader.read(new File(“文件地址以及文件名”)); |
(2)解析xml形式的文本,得到document对象
String text =”<members></menbers>”; Document document = DocumentHelper.parseText(text); |
(3)主动创建document对象
Document document = DocumentHelper.createDocument(); //创建根节点 Element root = document.addElement(“members”); |
5.4.3、节点对象
l 1、获取文档的根节点
Element root = document.getRootElement(); |
l 2、取得某个节点的子节点
Element element = node.element(“书名”); |
l 3、取得节点的文字
String text = node.getText(); |
l 4、取得某节点下所有名为“member”的子节点,并进行遍历
List nodes = rootEle.elements(“member”); for(Iterator it = nodes.iterator();it.hasNext();){ Element ele = (Element) it.next(); //do something } |
l 5、对某个节点的所有字典进行遍历
for(Iterator it = nodes.iterator();it.hasNext();){ Element ele = (Element) it.next(); //do something } |
l 6、在某节点下添加子节点
Element ageElm = newMemberElm.addElement("age"); |
l 7、设置节点文字
element.setText(“2345”); |
l 8、删除某节点
parentEle.remove(childEle); |
l 9、添加一个CDATA节点
Element contentElm = infoElm.addElement(“content”); contentElm.addCDATA(diary.getContent()); |
5.4.4、节点对象属性
l 1、取得某节点下的某属性
Element root = document.getRootElement(); Attribute attribute = root.attribute(“size”); |
l 2、取得属性的文字
String text = attribute.getText(); |
l 3、删除某属性
Attribute attribute = root.attribute(“size”); root.remove(); |
l 4、遍历某节点的所有属性
Element root = document.getRootElement(); for(Iterator it=root.attributeIterator;it.hasNext()){ Attribute attribute = attribute.getText(); String text = attribute.getText(); System.out.println(text); } |
l 5、设置某节点的属性和文字
newMemberEle.addAttribute(“name”,”sanjiang”); |
l 6、设置属性的文字
Attribute attribute = root.attribute(“name”); attribute.setText(“sanjiang”); |
5.4.5、Dom4j在指定位置插入节点
l 1、得到插入位置的节点列表(list);
l 2、调用list.add(index element),由index决定element的插入位置;
Element元素可以通过DocumentHelper对象得到;示例代码如下:
Element element = DocumentHelper.createElement(“element”); element.setText(“aaaa”); List list = root.element(“书”).elements(); list.add(1,aaa); //更新document |
l 3、将文档希尔xml文件
(1)文档中全为英文,不设置编码,直接写入的形式
XMLWriter writer = new XMLWriter(new FileWriter("output.xml")); writer.write(document); writer.close(); |
(2)文档中含有中问,设置编码格式写入的形式
OutputFormat format = OutputFormat.createPrettyPrint(); //指定xml编码 format.setEncoding("GBK"); XMLWriter writer = new XMLWriter(new FileWriter("output.xml"),format); writer.write(document); writer.close(); 出现乱码时使用以下代码: new OutputStreamWriter(new FileOutputStream("src/.."),"utf-8"); |
5.4.6、Dom4j入门案例
以下代码是allhero.xml文件,对其进行CRUD操作:
<?xml version="1.0" encoding="utf-8"?> <水浒> <英雄> <名字别名="及时雨">宋江</名字> <年龄>35</年龄> <介绍>首领</介绍> </英雄> <英雄> <名字别名="玉麒麟" >卢俊义</名字> <年龄>25</年龄> <介绍>二号首领</介绍> </英雄> <英雄> <名字别名="行者">武松</名字> <年龄>30</年龄> <介绍>行者武松</介绍> </英雄> </水浒> |
使用Dom4j解析代码如下所示:
package com.dom4j.test;
import java.io.File; import java.io.FileOutputStream; import java.util.Iterator; import java.util.List;
import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter;
public class Dom4jTest { public static void main(String[] args) throws Exception { // 1、得到解析器 SAXReader saxReader = new SAXReader(); // 2、指定需要解析的xml文件 Document document = saxReader.read(new File( "src/com/dom4j/test/allhero.xml")); // 遍历文件 list(document.getRootElement()); // 读取第一个英雄的信息 read(document); // 向xml文件中添加一个新的英雄 add(document); // 从xml文件中删除某个英雄 delete(document); // 在xml文件中的某个英雄后面添加新的英雄 addByIndex(document); }
@SuppressWarnings("unchecked") public static void addByIndex(Document document) throws Exception { // 首先创建一个新的英雄对象 Element newHero = DocumentHelper.createElement("英雄"); // 为对象添加属性 newHero.setText("李逵"); List<Element> allHeroes = document.getRootElement().elements("英雄"); for (int i = 0; i < allHeroes.size(); i++) { Element name = allHeroes.get(i).element("名字"); if (name.getText().equals("卢俊义")) { System.out.println("i=" + i); allHeroes.add(i + 1, newHero); break; } } // 设置输出的xml文件的格式,若不设置则会产生乱码 OutputFormat outputFormat = OutputFormat.createPrettyPrint(); outputFormat.setEncoding("UTF-8"); // 更新xml文件 XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(new File( "src/com/dom4j/test/allhero.xml")), outputFormat); xmlWriter.write(document); xmlWriter.close(); }
public static void delete(Document document) throws Exception { // 找到该元素 Element ele_hero = document.getRootElement().element("英雄") .element("名字"); // 删除该元素,通过得到该元素的父元素来删除 ele_hero.getParent().remove(ele_hero); // 设置输出的xml文件的格式,若不设置则会产生乱码 OutputFormat outputFormat = OutputFormat.createPrettyPrint(); outputFormat.setEncoding("UTF-8"); // 更新xml文件 XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(new File( "src/com/dom4j/test/allhero.xml")), outputFormat); xmlWriter.write(document); xmlWriter.close(); }
public static void add(Document document) throws Exception { // 首先创建一个新的英雄对象 Element newHero = DocumentHelper.createElement("英雄"); Element newHero_name = DocumentHelper.createElement("名字"); Element newHero_age = DocumentHelper.createElement("年龄"); Element newHero_intro = DocumentHelper.createElement("介绍"); // 为对象添加属性 newHero_name.setText("林冲"); newHero_name.addAttribute("别名", "豹子头"); // 关联子节点与父节点 newHero.add(newHero_name); newHero.add(newHero_age); newHero.add(newHero_intro); // 把父节点添加到根节点下 document.getRootElement().add(newHero); // 设置输出的xml文件的格式,若不设置则会产生乱码 OutputFormat outputFormat = OutputFormat.createPrettyPrint(); outputFormat.setEncoding("UTF-8"); // 更新xml文件 XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(new File( "src/com/dom4j/test/allhero.xml")), outputFormat); xmlWriter.write(document); xmlWriter.close(); }
public static void read(Document document) { // 得到根元素 Element element = document.getRootElement(); // element.elements("英雄") :表示取出 root元素下的所有英雄元素 // element.element("英雄") :表示取出 root元素下的第一个英雄元素 // element.elements("英雄").get(0) :表示取出 root元素下的第一个学生元素 Element hero = (Element) element.elements("英雄").get(0); Element hero_name = hero.element("名字"); System.out.println(hero_name.getText() + "别名" + hero_name.attributeValue("别名")); }
// 遍历根元素 @SuppressWarnings("unchecked") public static void list(Element element) { System.out.println(element.getName() + ":" + element.getTextTrim()); Iterator iterator = element.elementIterator(); while (iterator.hasNext()) { Element ele = (Element) iterator.next(); list(ele); } } } |
5.4.7、XPATH技术
XPATH技术解决了按层取得元素的问题。
具体案例详见其官方文档中案例。
6.1.1、使用dom解析xml文件
book.xml代码如下所示:
<?xml version="1.0" encoding="GBK"?> <书籍列表> <计算机书籍 ISBN="34553"> <书名>疯狂Java讲义</书名> <价格>99.00元</价格> <简要介绍>Java SE</简要介绍> </计算机书籍> <计算机书籍 ISBN="12345"> <书名>疯狂Java WEB讲义</书名> <价格>89.00元</价格> <简要介绍>Java WEB</简要介绍> </计算机书籍> <计算机书籍> <书名>疯狂XML讲义</书名> <价格>69.00元</价格> <简要介绍>XML</简要介绍> </计算机书籍> <文学书籍>不能承受的生命之轻</文学书籍> <哲学书籍> <书名>乌合之众</书名> 能提高人类对世界认识的书籍 </哲学书籍> </书籍列表> |
DomParse.java代码如下所示:
/** *使用DOM模型解析xml文档内容 */ package com.xml.dom; import java.io.File; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class DomParse { public static void main(String[] args) throws Exception { // DOM解析器工厂 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setIgnoringElementContentWhitespace(true); // 获取DOM解析器 DocumentBuilder builder = factory.newDocumentBuilder(); // 解析XML文档,并获取该XML文档对应的Document Document doc = builder.parse(new File("src/com/xml/dom/book.xml")); // 获取根节点的方法:getDocumentElement Element bookList = doc.getDocumentElement(); // 获取根元素所包含的所有“计算机书籍”子元素,如果传入*做参数,可获取所有子元素 NodeList nodeList = bookList.getElementsByTagName("计算机书籍"); // 遍历每个子元素 for (int i = 0; i < nodeList.getLength(); i++) { System.out.println("第" + i + "本计算机书籍"); Node comBook = nodeList.item(i); //获取ISBN属性节点 Node isbnAttr = comBook.getAttributes().getNamedItem("ISBN"); if (isbnAttr != null) { System.out.println("该图书的ISBN为" + isbnAttr.getTextContent()); } //获取comBook下的所有子元素 NodeList attList = comBook.getChildNodes(); //遍历每个子元素 for (int j = 0; j < attList.getLength(); j++) { System.out.println(attList.item(j).getTextContent().trim()); } } // 获取根元素所包含的所有“文学书籍”子元素 nodeList = bookList.getElementsByTagName("文学书籍"); // 遍历每个子元素 for (int i = 0; i < nodeList.getLength(); i++) { System.out.println("第" + i + "本文学书籍"); Node cultureBook = nodeList.item(i); System.out.println(cultureBook.getTextContent()); } // 获取根元素所包含的所有“哲学书籍”子元素 nodeList = bookList.getElementsByTagName("哲学书籍"); // 遍历每个子元素 for (int i = 0; i < nodeList.getLength(); i++) { System.out.println("第" + i + "本哲学书籍"); Node philosophyBook = nodeList.item(i); System.out.println(philosophyBook.getTextContent().trim()); System.out.println(philosophyBook.getFirstChild().getTextContent() .trim()); } } } |
6.1.2、使用dom创建xml文件
DomCreate.java代码如下所示:
/** *使用DOM模型创建xml文档 */ package com.xml.dom; import java.io.FileWriter; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Comment; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.ProcessingInstruction; import org.w3c.dom.bootstrap.DOMImplementationRegistry; import org.w3c.dom.ls.DOMImplementationLS; import org.w3c.dom.ls.LSOutput; import org.w3c.dom.ls.LSSerializer; public class DomCreate { public static void main(String[] args) throws Exception { // DOM解析器工厂 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setIgnoringElementContentWhitespace(true); // 获取DOM解析器 DocumentBuilder builder = factory.newDocumentBuilder(); // 创建一个新的Document对象 Document doc = builder.newDocument(); // 设置XML版本 doc.setXmlVersion("1.0"); // 创建处理指令 ProcessingInstruction pi = doc.createProcessingInstruction("sju", "href='www.sju.edu.cn'"); // 添加处理指令 doc.appendChild(pi); Comment comment = doc.createComment("根元素之前的注释"); // 创建根元素 Element root = doc.createElement("student"); // 为根元素添加学号属性 root.setAttribute("学号", "12010054052"); // 创建name元素 Element item = doc.createElement("name"); // 为name元素增加文本子节点 item.appendChild(doc.createTextNode("黄文伯")); // 将name元素添加到根元素之下 root.appendChild(item); // 创建age元素 item = doc.createElement("age"); // 为age元素增加文本子节点 item.appendChild(doc.createTextNode("24")); // 将age元素添加到根元素之下 root.appendChild(item); // 创建high元素 item = doc.createElement("high"); // 为high元素增加文本子节点 item.appendChild(doc.createTextNode("1.83")); // 将age元素添加到根元素之下 root.appendChild(item); // 创建score元素 item = doc.createElement("score"); // 创建Java元素 Element lesson = doc.createElement("Java"); // 为Java元素添加文本子元素 lesson.appendChild(doc.createTextNode("95")); // 将Java元素添加到score元素之下 item.appendChild(lesson); // 创建Struts元素 lesson = doc.createElement("Struts"); // 为Struts元素添加文本子元素 lesson.appendChild(doc.createTextNode("95")); // 将Struts元素添加到score元素之下 item.appendChild(lesson); // 创建Hibernate元素 lesson = doc.createElement("Hibernate"); // 为Hibernate元素添加文本子元素 lesson.appendChild(doc.createTextNode("85")); // 将Hibernate元素添加到score元素之下 item.appendChild(lesson); // 将score元素添加到根元素下 root.appendChild(item); // 为文档指定根元素 doc.appendChild(root); // 获取DOMImplementationRegistry对象,它是获取DOMImplementation的工厂 DOMImplementationRegistry registry = DOMImplementationRegistry .newInstance(); // 获取DOMImplementationLS对象 DOMImplementationLS domImplLS = (DOMImplementationLS) registry .getDOMImplementation("LS"); // 获取LSSerializer对象,他是专门用于序列化DOM树的工具 LSSerializer serializer = domImplLS.createLSSerializer(); // 设置使用合理缩进使得xml文档更加美观 serializer.getDomConfig().setParameter("format-pretty-print", true); LSOutput out = domImplLS.createLSOutput(); // 指定输出文档编码所用的字符集 out.setEncoding("GB2312"); FileWriter stringOut = new FileWriter("src/com/xml/dom/test.xml"); out.setCharacterStream(stringOut); // 执行序列化(将DOM树转换成XML文档) serializer.write(doc, out); } } |
结果生成create.xml文件,代码如下所示:
<?xml version="1.0" encoding="GB2312"?> <student 学号="12010054052"> <name>黄文伯</name> <age>24</age> <high>1.83</high> <score> <Java>95</Java> <Struts>95</Struts> <Hibernate>85</Hibernate> </score> </student> <?sju href='www.sju.edu.cn'?> |
6.1.3、使用dom更新 xml文件
DomUpdate.java代码如下所示:
/** * 使用DOM修改XML文档 */ package com.xml.dom; import java.io.FileWriter; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.bootstrap.DOMImplementationRegistry; import org.w3c.dom.ls.DOMImplementationLS; import org.w3c.dom.ls.LSOutput; import org.w3c.dom.ls.LSSerializer;
public class DomUpdate { public static void main(String[] args) throws Exception { // DOM解析器工厂 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setIgnoringElementContentWhitespace(true); // 获取DOM解析器 DocumentBuilder builder = factory.newDocumentBuilder(); // 创建一个新的Document对象 Document doc = builder.parse("src/com/xml/dom/create.xml"); // 获取文档中所有标签名为“name”的元素 NodeList names = doc.getElementsByTagName("name"); // 如果names节点列表不为null,且至少包含1个节点 if (names != null && names.getLength() > 0) { //获取第一个节点 Node name = names.item(0); //修改节点数据 name.setTextContent("dirk"); } // 获取DOMImplementationRegistry对象,它是获取DOMImplementation的工厂 DOMImplementationRegistry registry = DOMImplementationRegistry .newInstance(); // 获取DOMImplementationLS对象 DOMImplementationLS domImplLS = (DOMImplementationLS) registry .getDOMImplementation("LS"); // 获取LSSerializer对象,他是专门用于序列化DOM树的工具 LSSerializer serializer = domImplLS.createLSSerializer(); // 设置使用合理缩进使得xml文档更加美观 serializer.getDomConfig().setParameter("format-pretty-print", true); LSOutput out = domImplLS.createLSOutput(); // 指定输出文档编码所用的字符集 out.setEncoding("GB2312"); FileWriter stringOut = new FileWriter("src/com/xml/dom/update.xml"); out.setCharacterStream(stringOut); // 执行序列化(将DOM树转换成XML文档) serializer.write(doc, out); } } |
结果生成update.xml文件代码如下所示:
<?xml version="1.0" encoding="GB2312"?> <student 学号="12010054052"> <name>dirk</name> <age>24</age> <high>1.83</high> <score> <Java>95</Java> <Struts>95</Struts> <Hibernate>85</Hibernate> </score> </student> <?sju href='www.sju.edu.cn'?> |
6.2.1、使用sax解析xml文件
book.xml文件以及其约束文档book.dtd代码如下所示:
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE book SYSTEM "book.dtd"[ <!ELEMENT book (computer_book)*> <!ELEMENT book_name (#PCDATA)> <!ATTLIST computer_book intro_movie ENTITIES #IMPLIED> ] > <booklist> <computer_book intro-movie="movie"> <book_name>疯狂Java</book_name> <book_price>99.00元</book_price> </computer_book> </booklist> |
<?xml version="1.0" encoding="GB2312"?> <!ELEMENT computer_book ((book_name,book_price))> <!ELEMENT book_price (#PCDATA)> <!--下面定义一个符号--> <!NOTATION wmv SYSTEM "video/x-ms-wmv"> <!--只有外部实体才能是未解析实体--> <!ENTITY movie SYSTEM "http://www.sju.edu.cn/test.wmv" NDATA wmv> |
SAXParse类和MyHandler类代码如下所示:
/** * 使用XMLReader和SAXParser解析 */ package com.xml.sax; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; public class SaxParse { public static void main(String[] args) throws Exception{ System.out.println("--使用XMLReader解析--"); //创建XMLReader解析器 XMLReader reader = XMLReaderFactory.createXMLReader(); //注册ContentHandler解析器 reader.setContentHandler(new MyHandler()); //注册DTDHandler监听器 reader.setDTDHandler(new MyHandler()); reader.parse("src/com/xml/sax/book.xml"); System.out.println("--使用SAXParser解析--"); //创建SAX解析器工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); //创建SAX解析器工厂 SAXParser parser = factory.newSAXParser(); //开始解析XML文档 parser.parse("src/com/xml/sax/book.xml", new MyHandler()); } } |
package com.xml.sax; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class MyHandler extends DefaultHandler { // 定义一个成员变量来保存当前正在处理的Tag private String currentTag; // 每当处理文本数据是将触发该方法 @Override public void characters(char[] ch, int start, int length) throws SAXException { String content = new String(ch, start, length); if (content.trim().length() > 0) { System.out.println("<" + currentTag + ">元素的值是:" + content.trim()); }
} // 处理文档结束时触发该方法 @Override public void endDocument() throws SAXException { System.out.println("解析文档结束!"); } // 处理文档结束时触发该方法 @Override public void endElement(String uri, String localName, String qName) throws SAXException { System.out.println("处理元素结束:" + qName); } // 处理元素里命名空间属性结束是触发该方法 @Override public void endPrefixMapping(String prefix) throws SAXException { System.out.println("<" + currentTag + ">元素的命名空间属性的前缀:" + prefix); } // 处理元素内容中可忽略的空白是触发该方法 @Override public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
} // 解析处理指令是触发该方法 @Override public void processingInstruction(String target, String data) throws SAXException { System.out.println("当前处理的指令是:" + target); System.out.println("处理指令数据是:" + data); } // 跳过实体时触发该方法 @Override public void skippedEntity(String name) throws SAXException { System.out.println("SAX解析器跳过的实体名是:" + name); } // 开始解析文档时触发该方法 @Override public void startDocument() throws SAXException { System.out.println("解析文档开始!"); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { System.out.println("开始处理元素:" + qName); currentTag = qName; // attributes代表该元素包含的所有属性 int len = attributes.getLength(); if (len > 0) { System.out.println("<" + currentTag + ">元素的属性如下:"); for (int i = 0; i < len; i++) { System.out.println(attributes.getQName(i) + "--->" + attributes.getValue(i)); } } } // 开始处理元素里命名空间属性是触发该方法 @Override public void startPrefixMapping(String prefix, String uri) throws SAXException { System.out.println("<" + currentTag + ">元素的命名空间属性的前缀:" + prefix); System.out.println("<" + currentTag + ">元素的命名空间属性的URI为:" + uri); } // 当遇到DTD中的符号定义时触发该方法 @Override public void notationDecl(String name, String publicId, String systemId) throws SAXException { System.out.println("当前符号的名字是:" + name); System.out.println("当前符号的PUBLIC ID是:" + publicId); System.out.println("当前符号的SYSTEM ID是:" + systemId); } @Override public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException { System.out.println("当前未解析实体的名字是:" + name); System.out.println("当前未解析实体的PUBLIC ID是:" + publicId); System.out.println("当前未解析实体的SYSTEM ID是:" + systemId); System.out.println("当前未解析实体实体关联符号名是:" + notationName); } } |