XML概念,约束文档,解析
day01总结
今日内容
l XML语法
l XML约束之DTD
l XML解析器介绍
l XML解析之JAXP( DOM、SAX )
l DOM4J
l Schema
一、XML语法
XML概述
1 什么是XML
XML全称为Extensible Markup Language, 意思是可扩展的标记语言,它是 SGML(标准通用标记语言)的一个子集。
XML语法上和HTML比较相似,但HTML中的元素是固定的,而XML的标签是可以由用户自定义的。
W3C在1998年2月发布1.0版本;
W3C在2004年2月发布1.1版本,但因为1.1版本不能向下兼容1.0版本,所以1.1没有人用。同时,在2004年2月W3C又发布了1.0版本的第三版。我们要学习的还是1.0版本!!!
2 W3C组织
W3C是万维网联盟(World Wide Web Consortium)英文的缩写,它成立于1994年10月,以开放论坛的方式来促进开发互通技术(包括规格、指南、软件和工具),开发网络的全部潜能。万维网联盟(W3C)从1994年成立以来,已发布了90多份Web技术规范,领导着Web技术向前发展。
W3C认为自身不是官方组织,因此将它正式发布的规范称为推荐(建议)标准,意思是进一步标准化的建议,但是由于组织自身的权威性往往成为事实上的标准。
3 XML的作用
l 程序的配置文件(这也是最后大家使用XML最常见的目的);
l 数据交换:不同语言之间用来交换数据;
l 小型数据库:用来当数据库存储数据。
4 XML与HTML比较
l HTML的元素都是固定的,而XML可以自定义元素;
l HTML用浏览器来解析执行, XML的解析器通常需要自己来写(因为元素是自定义的);
l HTML只能用来表示网页,而XML可以做的事情很多。
5 XML和properties(属性文件)比较
l 属性文件只能存储平面信息,而XML可以存储结构化信息;
l 解析属性文件只需要使用Properties类就可以了,而解析XML文档是很复杂的。
XML语法概述
l 元素!!!
l 文档声明!!!
1 XML文档展示
<?xml version="1.0" encoding="utf-8" standalone="no"?> <students> <student number="1001"> <name>zhangSan</name> <age>23</age> <sex>male</sex> </student> <student number="1002"> <name>liSi</name> <age>32</age> <sex>female</sex> </student> <student number="1003"> <name>wangWu</name> <age>55</age> <sex>male</sex> </student> </students> |
2 XML文档的组成部分
l XML文档声明;重要
l XML处理指令;看完了,就可以忘了!
l XML元素;最重要
l XML特殊字符和CDATA区;一看就会
l XML注释。不看都会
XML文档声明
1 什么是xml文档声明
可以把xml文档声明看成是xml文档说明。
最简单的xml文档声明:<?xml version="1.0"?>
注意,XML是区别大小写,这一点不同与HTML!
2 xml文档声明结构
l version属性:用于说明当前xml文档的版本,因为都是在用1.0,所以这个属性值大家都写1.0,version属性是必须的;
l encoding属性:用于说明当前xml文档使用的字符编码集,xml解析器会使用这个编码来解析xml文档。encoding属性是可选的,默认为UTF-8。注意,如果当前xml文档使用的字符编码集是gb2312,而encoding属性的值为UTF-8,那么一定会出错的;
l standalone属性:用于说明当前xml文档是否为独立文档,如果该属性值为yes,表示当前xml文档是独立的,如果为no表示当前xml文档不是独立的,即依赖外部的文件。默认是yes
l 没有xml文档声明的xml文档,不是格式良好的xml文档;
l xml文档声明必须从xml文档的1行1列开始。
XML元素
1 XML元素的格式1
l xml元素包含:开始标签、元素体(内容)、结束标签。例如:<hello>大家好</hello>
l 空元素:空元素只有开始标签,没有元素体和结束标签,但空元素一定要闭合。例如:<hello/>
2 XML元素的格式2
l xml元素可以包含子元素或文本数据。例如:<a><b>hello</b></a>,a元素的元素体内容是b元素,而b元素的元素体内容是文本数据hello。
l xml元素可以嵌套,但必须是合法嵌套。例如:<a><b>hello<a></b>就是错误的嵌套。
3 XML文档的根元素
格式良好的xml文档必须且仅有一个根元素!
student1.xml
<?xml version="1.0" encoding="utf-8" standalone="no"?> <students> <student number="1001"> <name>zhangSan</name> <age>23</age> <sex>male</sex> </student> <student number="1002"> <name>liSi</name> <age>32</age> <sex>female</sex> </student> </students> |
student2.xml
<?xml version="1.0" encoding="utf-8" standalone="no"?> <student number="1001"> <name>zhangSan</name> <age>23</age> <sex>male</sex> </student> <student number="1002"> <name>liSi</name> <age>32</age> <sex>female</sex> </student> |
student1.xml是格式良好的xml文档,只有一个根元素,即students元素。
student2.xml不是格式良好的xml文档,有两个根元素,即两个student根元素。
4 元素中的空白
xml元素的元素体可以包含文本数据和子元素。
a.xml
<a><b>hello</b></a> |
b.xml
<a> <b> hello </b> </a> |
a.xml中,<a>元素只有一个子元素,即<b>元素。<b>元素只有一个文本数据,即hello。
b.xml中,<a>元素中第一部分为换行缩进,第二部分为<b>元素,第三部分为换行。b元素的文本数据为换行、缩进、hello、换行、缩进。
其中换行和缩进都是空白,这些空白是为了增强xml文档的可读性。但xml解析器可能会因为空白出现错误的解读,这说明在将来编写解析xml程序时,一定要小心空白。
5 元素命名规范
xml元素名可以包含字母、数字以及一些其它可见字符,但必须遵循下面的一些规范:
l 区分大小写:<a>和<A>是两个元素;
l 不能以数字或下划线开头:<1a>、<_a>都是错误的;
l 不能以xml开头:<xml>、<Xml>、<XML>都是错误的;
l 不能包含空格;
l 名称中间不能包含冒号:带有冒号的元素名是有特殊含义的
元素属性
l 属性由属性名与属性值构成,中间用等号连接;
l 属性值必须使用引号括起来,单引或双引;
l 定义属性必须遵循与标签名相同的命名规范;
l 属性必须定义在元素的开始标签中;
l 一个元素中不能包含相同的属性名;
l 有时属性和子元素可以互换,例如:<a><b>hello</b></a>可以改为<a b=”hello”></a>
注释
l 注释以<!--开头,以-->结束;
l 注释中不能包含-->;
l 注释不能以--->结束。
转义字符和CDATA区
因为在xml文档中有些字符是特殊的,不能使用它们作为文本数据。例如:不能使用“<”或“>”等字符作为文本数据,所以需要使用转义字符来表示。
例如<a><a></a>,你可能会说,其中第二个<a>是a元素的文本内容,而不是一个元素的开始标签,但xml解析器是不会明白你的意思的。
把<a><a></a>修饰为<a><a></a>,这就OK了。
转义字符都是以“&”开头,以“;”结束。这与后面我们学习的实体是相同的。
CDATA区(CDATA段)
当大量的转义字符出现在xml文档中时,会使xml文档的可读性大幅度降低。这时如果使用CDATA段就会好一些。
在CDATA段中出现的“<”、“>”、“””、“’”、“&”,都无需使用转义字符。这可以提高xml文档的可读性。
<a><![CDATA[<a>]]></a> |
在CDATA段中不能包含“]]>”,即CDATA段的结束定界符。
处理指令
处理指令,简称PI(Processing instruction)。处理指令用来指挥解析器如何解析XML文档内容。
例如,在XML文档中可以使用xml-stylesheet指令,通知XML解析器,应用css文件显示xml文档内容。
<?xml-stylesheet type="text/css" href="a.css"?> |
处理指令以“<?”开头,以“?>”结束,这一点与xml文档声明相同。
gj1 {font-size: 200px; color: red;} gj2 {font-size: 100px; color: green;} gj3 {font-size: 10px;} gj4 {font-size: 50px; color: blue;} |
<?xml version="1.0" encoding="gbk"?> <?xml-stylesheet type="text/css" href="a.css" ?> <gjm> <gj1>中国</gj1> <gj2>美国</gj2> <gj3>日本</gj3> <gj4>英国</gj4> </gjm> |
二、XML约束
XML约束概述
一个XML文档一旦有了约束,那么这个XML文档就只能使用约束中创建的元素及属性。如果约束没有创建<a>元素,那么XML文档就不能使用<a>元素!!!
1 什么是xml约束
因为xml文档是可以自定义元素的,这会让使用xml文档的应用程序无法知道xml文档的真实结构。通常应用程序都会要求xml文件的结构是固定的,以满足自己的需求,这就说明,不同的应用程序要求自己的xml文档必须符合一定的要求。
例如,当使用xml文档作为某个Java swing应用程序的配置文件时,要求xml文档结构如下:
<frame title="test xml" layout="java.awt.BorderLayout"> <bgcolor> <red>200</red> <green>0</green> <blue>0</blue> </bgcolor> <size> <width>300</width> <heigth>200</heigth> </size> <content> <label> <text>hello xml</text> <label> </content> </frame> |
当某个学生管理系统程序需要使用xml文档作为数据库时,要求xml文档结构如下:
<?xml version="1.0" encoding="utf-8" standalone="no"?> <students> <student number="1001"> <name>zhangSan</name> <age>23</age> <sex>male</sex> </student> <student number="1002"> <name>liSi</name> <age>32</age> <sex>female</sex> </student> <student number="1003"> <name>wangWu</name> <age>55</age> <sex>male</sex> </student> </students> |
xml文档约束是用另一个文件来约束xml文档的结构,例如要求xml文档的根元素必须是<students>,在<students>元素下可以包含0~n个<student>元素,每个<student>元素必须有一个number属性,而且还要有三个子元素,分别为<name>、<age>、<sex>,这三个子元素的内容必须为文本内容,而不能是子元素。
2 XML文档约束的类型
xml文档约束有两种类型:dtd和schema
l dtd:dtd是平面式文档,dtd文件不是xml文档,通常扩展名为“.dtd”。它是最早的xml约束;
l schema:schema本身也是xml文档,它比dtd要更加强大,通常扩展名为“.xsd”。它是新的xml文档约束,用来替代dtd。
DTD是老的XML约束
Schema是新的,用Schema替换掉DTD
会读即可!
DTD
1 什么是DTD
DTD(Document Type Definition),文档类型定义,用来约束XML文档。例如要求xml文档的根元素必须是<students>,在<students>元素下可以包含0~n个<student>元素,每个<student>元素必须有一个number属性,而且还要有三个子元素,分别为<name>、<age>、<sex>,这三个子元素的内容必须为文本内容,而不能是子元素。
2 DTD展示
<!ELEMENT students (student+)> <!ELEMENT student (name,age,sex)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT sex (#PCDATA)> |
解读上面DTD:
l students元素中可以包含1~n个student元素;
l student元素中必须包含name、age、sex元素,而且顺序也是固定的;
l name元素内容为文本,即字符串;
l age元素内容为文本;
l sex元素内容为文本。
3 在XML文档中指定本地DTD
<?xml version="1.0" encoding="utf-8" standalone="no" ?> <!DOCTYPE students SYSTEM "students.dtd"> <students> <student> <name>zhangSan</name> <age>23</age> <sex>male</sex> </student> </students> |
<!ELEMENT students (student+)> <!ELEMENT student (name, age, sex)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT sex (#PCDATA)> |
其中<!DOCTYPE students SYSTEM "students.dtd">,表示指定dtd文件。
指定DTD的语法:<!DOCTYPE 根元素 SYSTEM "DTD文件路径">
l 指定DTD的语法,以“<!DOCTYPE”开头,以“>”结束;
l students表示根元素;
l SYSTEM表示dtd文件在本地;
l "students.dtd"表示DTD文件路径。
4 在XML文档中指定内部DTD
<?xml version="1.0" encoding="utf-8" standalone="no" ?> <!DOCTYPE students [ <!ELEMENT students (student+)> <!ELEMENT student (name, age, sex)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT sex (#PCDATA)> ]> <students> <student> <name>zhangSan</name> <age>23</age> <sex>male</sex> </student> </students> |
5 在XML文档中指定外部公共DTD
<?xml version="1.0" encoding="utf-8" standalone="no" ?> <!DOCTYPE students PUBLIC "-//qdmmy6//DTD ST 1.0//ZH" "http://www.qdmmy6.com/xml/dtds/st.dtd"> <students> <student> <name>zhangSan</name> <age>23</age> <sex>male</sex> </student> </students> |
外部公共DTD是说,DTD由某个公司或权威组织发布,例如如下:
<!DOCTYPE 根元素 PUBLIC "DTD名称" "DTD网址">
当然你需要知道要使用的DTD的名称和网址。如果某个机构公布了DTD,那么一定也会公布DTD的名称和网址。
上面例子中的公共DTD是不存在的。
DTD定义元素
1 定义元素的语法
使用ELEMENT声明元素:<!ELEMENT 元素名 内容类型或内容>
例如:<!ELEMENT name (#PCDATA)>
表示name元素的内容为文本数据
2 元素类型
元素类型可以是ANY或EMPTY
<!ELEMENT stu ANY>:表示stu元素的内容可以是任意元素,也可以是文本数据,也可以是文本数据+子元素,反正就是任意。
<!ELEMENT stu EMPTY>:表示stu不能有任何内容,即空元素。例如:<stu/>。
3 元素内容
元素内容可以是文本数据,也可以是子元素
<!ELEMENT stu (#PCDATA)>表示stu元素内容为文本,例如:<stu>hello</stu>
<!ELEMENT stu (name)>表示stu元素内容为name子元素,例如<stu><name></name><stu>,但要注意,如果<name>元素没有声明,那么就会出错。
4 子元素出现次数
可以使用“?”、“*”、“+”来指定子元素的出现次数
<!ELEMENT stu (name?)>表示stu元素可以有0~1个name子元素,即name子元素可有可无。
<!ELEMENT stu(name*)>表示stu元素可以有0~n个name子元素;
<!ELEMENT stu(name+)>表示stu元素可以有1~n个name子元素。
5 多个子元素
<!ELEMENT stu (name,age,sex)>表示stu必须有三个子元素,分别是name、age、sex,并且子元素出现的顺序也要与声明的顺序一致。
6 枚举子元素
<!ELEMENT stu (name | age | sex)表示stu只有一个子元素,可以是name、age、sex中的任意一个。
7 复合声明1
<!ELEMENT stu (name | age | sex)?>表示stu元素可以有0~1个(name | age | sex),而(name | age | sex)表示name、age、sex其中的一个。
<stu></stu>
<stu><name/></stu>
<stu><age/></stu>
<stu><sex/></stu>
8 复合声明2
<!ELEMENT stu (name | age | sex)*>表示stu元素可以有0~n个(name | age | sex),而(name | age | sex)表示name、age、sex其中的一个。
<stu></stu>
<stu><name/><name/></stu>
<stu><name/><age/><age/></stu>
<stu><name/><age/><name/><sex/><sex/></stu>
9 复合声明3
<!ELEMENT stu (name | age | sex)+>表示stu元素可以有1~n个(name | age | sex),而(name | age | sex)表示name、age、sex其中的一个。
<stu><age/></stu>
<stu><name/><name/></stu>
<stu><name/><age/><age/></stu>
<stu><name/><age/><name/><sex/><sex/></stu>
10 练习
<!DOCTYPE 课件 [ <!ELEMENT 章节 (简介, (标题, (段落 | 图片 | 表格 | 说明)+)+)> <!ELEMENT 简介 (#PCDATA)> <!ELEMENT 标题 (#PCDATA)> <!ELEMENT 段落 (#PCDATA)> <!ELEMENT 图片 (#PCDATA)> <!ELEMENT 表格 (#PCDATA)> <!ELEMENT 说明 (#PCDATA)> <!ELEMENT 课件 (章节+)> ]> |
根据上面DTD写xml文档!!!
DTD属性定义
1 属性定义的格式
Attribute List
<!ATTLIST 元素名
属性名1 属性类型 设置说明
属性名2 属性类型 设置说明
...>
<!ATTLIST student number CDATA #REQUIRED>表示student元素的number为文本类型,这个属性是必须的。
最常见的属性类型:CDATA,表示文本类型;
最常见的设置说明1:#REQUIRED,表示属性是必须的。
最常见的设置说明2:#IMPLIED,表示属性是可选的。
2 属性类型
l CDATA:属性值为任意文本数据;
l Enumerated:属性值必须是枚举列表中的一个;
l ID:属性值必须是唯一的,并且属性值不能以数字开头;
3 CDATA属性类型
CDATA,即Character Data(字符数据)。表示属性的类型为字符类型!
<!ATTLIST student number CDATA #REQUIRED>表示student元素的number属性是字符数据类型,并且是必须属性。
<student number=”czbk_1001”>
4 Enumerated属性类型
Enumerated不是关键字,定义枚举类型的属性需要给出枚举列表。当属性值为枚举类型时,那么这个属性的取值必须是枚举列表中的一个值。
<!ATTLIST student sex (male | female) #IMPLIED> 表示student的sex属性取值必须是male或者是female。并且这个属性是可选的。
5 ID属性类型
一个元素最多只能有一个ID 属性,ID属性用来表示元素唯一性的唯一标识。ID属性就相当与元素的身份证号,必须是唯一标识!
如果把student元素的number属性设定为ID类型,那么每个student元素的number属性值必须是唯一的,并且ID类型的属性值不能以数字开头。
<!ATTLIST student number ID #REQUIRED> 表示student的number属性值是ID类型,这说明student元素的number属性值必须是唯一的,不能和其他student的number属性值相同。
<student number=”czbk_1001”/>
<student number=”czbk_1002”/>
注意:不能以数字开头。
如果<a>元素有一个ID属性a
如果<b>元素有一个ID属性b
<a a=”abc”/>
<b b=”abc”/>
上面也是错误的,因为ID属性的值是不可以相同的。
6 设置说明
l #REQUIRED:表示属性是必须的;
l #IMPLIED:表示属性是可选的,即这个属性可以不给出;
三、XML解析器介绍
操作XML文档概述
1 如何操作XML文档
XML文档也是数据的一种,对数据的操作也不外乎是“增删改查”。也被大家称之为“CRUD”。
l C:Create;
l R:Retrieve;
l U:Update;
l D:Delete
2 XML解析技术
XML解析方式分为两种:DOM(Document Object Model)和SAX(Simple API for XML)。这两种方式不是针对Java语言来解析XML的技术,而是跨语言的解析方式。例如DOM还在Javascript中存在!
DOM是W3C组织提供的解析XML文档的标准接口,而SAX是社区讨论的产物,是一种事实上的标准。
DOM和SAX只是定义了一些接口,以及某些接口的缺省实现,而这个缺省实现只是用空方法来实现接口。一个应用程序如果需要DOM或SAX来访问XML文档,还需要一个实现了DOM或SAX的解析器,也就是说这个解析器需要实现DOM或SAX中定义的接口。提供DOM或SAX中定义的功能。
解析原理
1 DOM解析原理
使用DOM要求解析器把整个XML文档装载到一个Document对象中。Document对象包含文档元素,即根元素,根元素包含N多个子元素…
一个XML文档解析后对应一个Document对象,这说明使用DOM解析XML文档方便使用,因为元素与元素之间还保存着结构关系。
优先:使用DOM,XML文档的结构在内存中依然清晰。元素与元素之间的关系保留了下来!
缺点:如果XML文档过大,那么把整个XML文档装载进内存,可能会出现内存溢出的现象!
2 设置Java最大内存
运行Java程序,指定初始内存大小,以及最大内存大小。
java -Xms20m -Xmx100m MyClass
3 SAX解析原理
DOM会一行一行的读取XML文档,最终会把XML文档所有数据存放到Document对象中。SAX也是一行一行的读取XML文档,但是当XML文档读取结束后,SAX不会保存任何数据,同时整个解析XML文档的工作也就结束了。
但是,SAX在读取一行XML文档数据后,就会给感兴趣的用户一个通知!例如当SAX读取到一个元素的开始时,会通知用户当前解析到一个元素的开始标签。而用户可以在整个解析的过程中完成自己的业务逻辑,当SAX解析结束,不会保存任何XML文档的数据。
优先:使用SAX,不会占用大量内存来保存XML文档数据,效率也高。
缺点:当解析到一个元素时,上一个元素的信息已经丢弃,也就是说没有保存元素与元素之间的结构关系,这也大大限制了SAX的使用范围。如果只是想查询XML文档中的数据,那么使用SAX是最佳选择!
解析器概述
1 什么是XML解析器
DOM、SAX都是一组解析XML文档的规范,其实就是接口,这说明需要有实现者能使用,而解析器就是对DOM、SAX的实现了。一般解析器都会实现DOM、SAX两个规范!
l Crimson(sun):JDK1.4之前,Java使用的解析器。性能效差,可以忘记它了!
l Xerces(IBM):IBM开发的DOM、SAX解析器,现在已经由Apache基金会维护。是当前最为流行的解析器之一!在1.5之后,已经添加到JDK之中,也是JAXP的默认使用解析器,但不过在JDK中的包名与Xerces不太一样。例如:org.apache.xerces包名改为了com.sun.org.apache.xerces.internal包名,也就是说JDK1.5中的Xerces是被包装后的XML解析器,但二者区别很小。
l Aelfred2(dom4j):DOM4J默认解析器,当DOM4J找不到解析器时会使用他自己的解析器。
JAXP概述
1 什么是JAXP
JAXP是由Java提供的,用于隐藏底层解析器的实现。Java要求XML解析器去实现JAXP提供的接口,这样可以让用户使用解析器时不依赖特定的XML解析器。
JAXP本身不是解析器(不是Xerces),也不是解析方式(DOM或SAX),它只是让用户在使用DOM或SAX解析器时不依赖特点的解析器。
当用户使用JAXP提供的方式来解析XML文档时,用户无需编写与特定解析器相关的代码,而是由JAXP通过特定的方式去查找解析器,来解析XML文档。
2 JAXP对DOM的支持
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse("src/students.xml"); |
在javax.xml.parsers包中,定义了DOM解析器工厂类DocumentBuilderFactory,用于产生DOM解析器。DocumentBuilderFactory是一个抽象类,它有一个静态方法newInstance(),可以返回一个本类的实例对象。其实该方法返回的是DocumentBuilderFactory类的子类的实例(即工厂实例对象)。那么这个子类又是哪个子类呢?其实这个子类是由XML解析器提供商提供的,不同的厂商提供的工厂类对抽象工厂的实现是不同的。然后由工厂实例创建解析器对象。
那么newInstance()这个方法又是如果找到解析器提供商的工厂类的呢?此方法使用下面有序的查找过程来确定要加载的DocumentBuilderFactory实现类:
一、使用javax.xml.parsers.DocumentBuilderFactory系统属性。如果设置了这个系统属性的值,那么newInstance()方法就以这个属性的值来构造这个工厂的实例。通过下面的方法可以设置这个系统属性值。
System.setProperty(“javax.xml.parsers.DocumentBuilderFactory”, “工厂实现类名字”);
我们不建议大家用上面的方法来硬编码这个系统属性的值,如果这样设置,假如将来需要更换解析器,就必需修改代码。
二、如果你没有设置上面的系统属性,newInstance()方法就会采用下面的途径来查找抽象工厂的实现类。第二个途径在查找JRE下的lib子目录下的jaxp.properties文件。如果这个文件存在,那么就读取这个文件。我们可以在%JAVA_HOME%\jre\lib\目录下创建一个jaxp.properties文件。在这个文件中给出一个键值对。如下所示:
javax.xml.parsers.DocumentBuilderFactory=工厂实现类名字
这个key名字必须是javax.xml.parsers.DocumentBuilderFactory,而相对应的值也必须设置类路径。
三、如果通过前两种途径下没有找到工厂的实现类,那么就需要使用服务API。这个服务API实际上是查找一个JAR文件的META-INF\ services\ javax.xml.parsers.DocumentBuilderFactory这个文件(该文件无扩展名)。如果找到了这个文件,就以这个文件的内容做为工厂实现类。这种方式被大多数解析器提供商所采用。在它们发布的解析器JAR包中往往会找到上述文件。然后在这个文件当中指定自己解析器的工厂类的名字。我们只需要把这个JAR文件的路径写到类路径(classpath)中就可以了。但要注意的是,如果在你的classpath中有多个解析器的JAR包路径,这时以前面的类路径优先。
四、如果说在前三种途径中都没有找到工厂实现类,那么就使用平台缺省工厂实现类。
在JAXP的早期的版本(5.0以前)中,除了JAXP API外,还包含了一个叫做Crimson的解析器。从JAXP1.2开始,Sun公司对Apache的Xerces解析器重新包装了一下,并将org.apache.xerces包名改为了com.sun.org.apache.xerces.internal,然后在JAXP的开发包中一起提供,作为缺省的解析器。我们所使用的JDK1.5中包含的缺省解析器就是被重新包装过后的Xerces解析器。
在获取到某个特定解析器厂商的DocumentBuilderFactory后,那么这个工厂对象创建出来的解析器对象当然就是自己厂商的解析器对象了。
3 JAXP对SAX的支持
SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); parser.parse("src/students.xml", new DefaultHandler() { public void startDocument() throws SAXException { System.out.println("解析开始"); }
public void endDocument() throws SAXException { System.out.println("解析结束"); }
public void processingInstruction(String target, String data) throws SAXException { System.out.println("处理指令"); }
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { System.out.println("元素开始:" + qName); }
public void characters(char[] ch, int start, int length) throws SAXException { System.out.println("文本内容:" + new String(ch, start, length).trim()); }
public void endElement(String uri, String localName, String qName) throws SAXException { System.out.println("元素结束:" + qName); } }); |
JAXP对SAX的支持与JAXP对DOM的支持是相同的,这里就不在赘述!
JDOM和DOM4J
1 JDOM和DOM4J概述
JDOM和DOM4J都是针对Java解析XML设计的方式,它们与DOM相似。但DOM不是只针对Java,DOM是跨语言的,DOM在Javascript中也可以使用。而JDOM和DOM4J都是专业为Java而设计的,使用JDOM和DOM4J,对Java程序员而言会更加方便。
2 JDOM和DOM4J比较
JDOM与DOM4J相比,DOM4J完胜!!!所以,我们应该在今后的开发中,把DOM4J视为首选。
在2000年,JDOM开发过程中,因为团队建议不同,分离出一支队伍,开发了DOM4J。DOM4J要比JDOM更加全面。
3 DOM4J查找解析器的过程
DOM4J首先会去通过JAXP的查找方法去查找解析器,如果找到解析器,那么就使用之;否则会使用自己的默认解析器Aelfred2。
DOM4J对DOM和SAX都提供了支持,可以把DOM解析后的Document对象转换成DOM4J的Document对象,当然了可以把DOM4J的Document对象转换成DOM的Document对象。
DOM4J使用SAX解析器把XML文档加载到内存,生成DOM对象。当然也支持事件驱动的方式来解析XML文档。
XML解析之JAXP(DOM)
JAXP获取解析器
1 JAXP相关包
JAXP相关开发包:javax.xml
DOM相关开发包:org.w3c.dom
SAX相关开发包:org.xml.sax
2 JAXP与DOM、SAX解析器的关系
JAXP只是作用只是为了让使用者不依赖某一特定DOM、SAX的解析器实现,当使用JAXP API时,使用者直接接触的就是JAXP API,而不用接触DOM、SAX的解析器实现API。
3 JAXP获取DOM解析器
当我们需要解析XML文档时,首先需要通过JAXP API解析XML文档,获取Document对象。然后用户就需要使用DOM API来操作Document对象了。
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse("src/students.xml"); |
4 JAXP保存Document
当我们希望把Document保存到文件中去时,可以使用Transformer对象的transform()方法来完成。想获取Transformer对象,需要使用TransformerFactory对象。
与JAXP获取DOM解析器一样,隐藏了底层解析器的实现。也是通过抽象工厂来完成的,这里就不在赘述了。
TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer(); trans.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); trans.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "students.dtd"); trans.setOutputProperty(OutputKeys.INDENT, "yes"); Source source = new DOMSource(doc); Result result = new StreamResult(xmlName); transformer.transform(source, result); |
|
Transformer类的transform()方法的两个参数类型为:Source和Result,DOMSource是Source的实现类,StreamResult是Result的实现类。
5 JAXP创建Document
有时我们需要创建一个Document对象,而不是从XML文档解析而来。这需要使用DocumentBuider对象的newDocument()方法。
DocumentBuilderFactory factory = DocumentBuilderFactory .newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.newDocument(); doc.setXmlVersion("1.0"); doc.setXmlStandalone(true); |
5 学习DOM之前,先写两个方法
l Document getDocument(String xmlName):通过xmlName获取Document对象;
l void saveDocument(Document doc, String xmlName):保存doc到xmlName文件中。
DOM API概述
1 Document对应XML文档
无论使用什么DOM解析器,最终用户都需要获取到Document对象,一个Document对象对应整个XML文档。也可以这样说,Document对象就是XML文档在内存中的表示形式。
通常我们最为“关心”的就是文档的根元素。所以我们必须要把Document获取根元素的方法记住:Element getDocumentElement()。然后通过根元素再一步步获取XML文档中的数据。
2 DOM API中的类
在DOM中提供了很多接口,用来描述XML文档中的组成部分。其中包括:文档(Document)、元素(Element)、属性(Attr)、文本(Text)、注释(Comment)、CDATA段(CDATASection)等等。无论是哪种XML文档组成部分,都是节点(Node)的子接口。
3 Node方法介绍
Node基本方法:
l String getNodeName():获取当前节点的名字。如果当前节点是Element,那么返回元素名称。如果当前节点是Text那么返回#text。如果当前节点是Document那么返回#document;
l String getNodeValue():获取当前节点的值。只有文本节点有值,其它节点的值都为null;
l String getTextContext():获取当前节点的文本字符串。如果当前节点为Text,那么获取节点内容。如果当前节点为Element,那么获取元素中所有Text子节点的内容。例如当前节点为:<name>zhangSan</name>,那么本方法返回zhangSan。如果当前节点为:<student><name>zhangSan</name><age>23</age><sex>male</sex></student>,那么本方法返回zhangSan23male。
l short getNodeType():获取当前节点的类型。Node中有很多short类型的常量,可以通过与这些常量的比较来判断当前节点的类型。if(node.getNodeType() == Node.ELEMENT_NODE);
Node获取子节点和父节点方法,只有Document和Element才能使用这些方法:
l NodeList getChildNodes():获取当前节点的所有子节点。NodeList表示节点列表,它有两个方法:
- int getLength():获取集合长度;
- Node item(int index):获取指定下标的节点。
l Node getFirstNode():获取当前节点的第一个子节点;
l Node getLastNode():获取当前节点的最后一个子节点;
l Node getParentNode():获取当前节点的父节点。注意Document的父节点为null。
Node获取弟兄节点的方法,只有Element才能使用这些方法:
l Node getNextSibling():获取当前节点的下一个兄弟节点;
l Node getPreviousSibling():获取当前节点的上一个兄弟节点。
Node添加、替换、删除子节点方法:
l Node appendChild(Node newChild):把参数节点newChild添加到当前节点的子节点列表的末尾处。返回值为被添加的子节点newChild对象,方便使用链式操作。如果newChild在添加之前已经在文档中存在,那么就是修改节点的位置了;
l Node insertBefore(Node newChild, Node refNode):把参数节点newChild添加到当前节点的子节点refNode之前。返回值为被添加的子节点newChild对象,方便使用链式操作。如果refNode为null,那么本方法与appendNode()方法功能相同。如果newChild节点在添加之前已经在文档中存在,那么就是修改节点的位置了。
l Node removeNode(Node oldChild):从当前节点中移除子元素oldChild。返回值为被添加的子节点oldChild对象,方便使用链式操作。
l Node replaceNode(Node newChild, Node oldChild):将当前节点的子节点oldChild替换为newChild。
Node获取属性集合方法,只有Element可以使用:
l NamedNodeMap getAttributes():返回当前节点的属性集合。NamedNodeMap表示属性的集合,方法如下:
- int getLength():获取集合中属性的个数;
- Node item(int index):获取指定下标位置上的属性节点;
- Node getNamedItem(String name):获取指定名字的属性节点;
- Node removeNamedItem(String name):移除指定名字的属性节点,返回值为移除的属性节点;
- Node setNamedItem(Node arg):添加一个属性节点,返回值为添加的属性节点。
Node的判断方法:
l boolean hasChildNodes():判断当前节点是否有子节点;
l boolean hasAttribute():判断当前节点是否有属性。
4 Docment方法介绍
创建节点方法:
l Attr createAttribute(String name):创建属性节点;
l CDATASection createCDATASection(String data):创建CDATA段节点;
l Comment createComment(String data):创建注释;
l Element createElement(String tagName):创建元素节点;
l Text createTextNode(String data):创建文本节点;
获取子元素方法:
l Element getElementById(String elementId):通过元素的ID属性获取元素节点,如果没有DTD指定属性类型为ID,那么这个方法将返回null;
l NodeList getElementsByTagName(String tagName):获取指定元素名称的所有元素;
l Element getDocumentElement():获取文档元素,即获取根元素。
文档声明相关方法:
l String getXmlVersion():获取文档声明的version属性值;
l String getXmlEncoding():获取文档声明的encoding属性值;
l String getXmlStandalone():获取文档声明的standalone属性值;
l void setXmlVersion():设置文档声明version属性值;
l void setXmlStandalone():设置文档声明standalone属性值。
5 Element方法介绍
获取方法:
l NodeList getElementsByTagName(String tagName):获取当前元素的指定元素名称的所有子元素;
l String getTagName():获取当前元素的元素名。调用元素节点的getNodeName()也是返回名;
属性相关方法:
l String getAttribute(String name):获取当前元素指定属性名的属性值;
l Attr getAttributeNode(String name):获取当前元素指定属性名的属性节点;
l boolean hasAttribute(String name):判断当前元素是否有指定属性;
l void removeAttribute(String name):移除当前元素的指定属性;
l void removeAttributeNode(Attr attr):移除当前元素的指定属性;
l void setAttribute(String name, String value):为当前元素添加或修改属性;
l Attr setAttributeNode(Attr attr):为当前元素添加或修改属性,返回值为添加的属性;
6 Attr方法介绍
l String getName():获取当前属性节点的属性名;
l String getValue():获取当前属性节点的属性值;
l void setValue(String value):设置当前属性节点的属性值;
l boolean isId():判断当前属性节点是否为ID类型属性。
SAX
SAX概述
1 SAX解析原理
首先我们想一下,DOM解析器是不是需要把XML文档遍历一次,然后把每次读取到的数据转换成节点对象(到底哪一种节点对象,这要看解析时遇到了什么东西)保存起来,最后生成一个Document对象返回。也就是说,当你调用了builder.parse(“a.xml”)后,这个方法就会把XML文档中的数据转换成节点对象保存起来,然后生成一个Document对象。这个解析XML文档的过程在parse()方法调用结束后也就结束了。我们的工作是在解析之后,开始对Document对象进行操作。
但是SAX不同,当SAX解析器的parse()方法调用结束后,不会给我们一个Document对象,而是什么都不给。SAX不会把XML数据保存到内存中,如果我们的解析工作是在SAX解析器的parse()方法调用结束后开始,那么就已经晚了!!!这说明我们必须在SAX解析XML文档的同时完成我们的工作。
SAX解析器在解析XML文档的过程中,读取到XML文档的一个部分后,会调用ContentHandler(内部处理器)中的方法。例如当SAX解析到一个元素的开始标签时,它会调用ContentHandler的startElement()方法;在解析到一个元素的结束标签时会调用ContentHandler的endElement()方法。
ContentHandler是一个接口,我们的工作是编写该接口的实现类,然后创建实现类的对象,在SAX解析器开始解析之前,把我们写的内容处理类对象交给SAX解析器,这样在解析过程中,我们的内容处理中的方法就会被调用了。
2 获取SAX解析器
与DOM相同,你应该通过JAXP获取SAX解析器,而不是直接使用特定厂商的SAX解析器。JAXP查找特定厂商的SAX解析器实现的方式与查找DOM解析器实现的方式完全相同,这里就不在赘述了。
SAXParserFactory factory = SAXParserFactory.newInstance(); javax.xml.parsers.SAXParser parser = factory.newSAXParser(); parser.parse("src/students.xml", new MyContentHandler()); |
上面代码中,MyContentHandler就是我们自己需要编写的ContentHandler的实现类对象。
3 内容处理器
org.xml.sax.ContentHandler中的方法:
l void setDocumentLocator(Locator locator):与定位相关,例如获取行数、实体、标识等信息,我们可以忽略他的存在;
l void startDocument() throws SAXException:文档开始解析之前被调用;
l void endDocument() throws SAXException:文档解析结束之后被调用;
l void startPrefixMapping(String prefix,String uri)throws SAXException:与名称空间相关,忽略;
l void endPrefixMapping(String prefix) throws SAXException:与名称空间相关,忽略;
l void startElement(String uri,String local,String qName,Attributes atts)throws SAXException:开始解析一个元素时被调用,其中uri、local这两个参数与名称空间相关,可以忽略。qName表示当前元素的名称,atts表示当前元素的属性集合;
l void endElement(String uri,String localName,String qName)throws SAXException:一个元素解析结束后会被调用;
l void characters(char[] ch,int start,int length)throws SAXException:解析到文本数据时会被调用,ch表示当前XML文档所有内容对应的字符数组,不只是当前文本元素的内容。start表示当前文本数据在整个XML文档中的开始下载位置,length是当前文本数据的长度;
l void ignorableWhitespace(char[] ch,int start,int length)throws SAXException:解析到空白文本数据时会被调用,可以忽略!
l void processingInstruction(String target,String data)throws SAXException:解析到处理指令时会被调用,可以忽略!
l void skippedEntity(String name)throws SAXException:解析到实体时会被调用,可以忽略!
org.xml.sax.helpers.DefualtHandler对ContentHandler做了空实现,所以我们可以自定义内容处理器时可以继承DefaultHandler类。
SAX应用
1 测试SAX
public class SAXTest { @Test public void testSAX() throws ParserConfigurationException, SAXException, IOException { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); parser.parse("src/students.xml", new MyContentHandler()); } private static class MyContentHandler extends DefaultHandler { @Override public void startDocument() throws SAXException { System.out.println("开始解析..."); } @Override public void endDocument() throws SAXException { System.out.println("解析结束..."); } @Override public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { System.out.println(qName + "元素解析开始"); } @Override public void endElement(String uri, String localName, String qName) throws SAXException { System.out.println(qName + "元素解析结束"); } @Override public void characters(char[] ch, int start, int length) throws SAXException { String s = new String(ch, start, length); if(s.trim().isEmpty()) { return; } System.out.println("文本内容:" + s); } @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("处理指令"); } } } |
2 使用SAX打印XML文档
public class SAXTest2 { @Test public void testSAX() throws ParserConfigurationException, SAXException, IOException { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); parser.parse("src/students.xml", new MyContentHandler()); } private static class MyContentHandler extends DefaultHandler { @Override public void startDocument() throws SAXException { System.out.println("<?xml version='1.0' encoding='utf-8'?>"); }
@Override public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { StringBuilder sb = new StringBuilder(); sb.append("<").append(qName); for(int i = 0; i < atts.getLength(); i++) { sb.append(" "); sb.append(atts.getQName(i)); sb.append("="); sb.append("'"); sb.append(atts.getValue(i)); sb.append("'"); } sb.append(">"); System.out.print(sb); }
@Override public void endElement(String uri, String localName, String qName) throws SAXException { System.out.print("</" + qName + ">"); }
@Override public void characters(char[] ch, int start, int length) throws SAXException { System.out.print(new String(ch, start, length)); } } } |
DOM4J
DOM4J概述
1 DOM4J是什么
DOM4J是针对Java开发人员专门提供的XML文档解析规范,它不同与DOM,但与DOM相似。DOM4J针对Java开发人员而设计,所以对于Java开发人员来说,使用DOM4J要比使用DOM更加方便。
DOM4J对DOM和SAX提供了支持,使用DOM4J可以把org.dom4j.document转换成org.w3c.Document,DOM4J也支持基于SAX的事件驱动处理模式。
使用者需要注意,DOM4J解析的结果是org.dom4j.Document,而不是org.w3c.Document。DOM4J与DOM一样,只是一组规范(接口与抽象类组成),底层必须要有DOM4J解析器的实现来支持。
DOM4J使用JAXP来查找SAX解析器,然后把XML文档解析为org.dom4j.Document对象。它还支持使用org.w3c.Document来转换为org.dom4j.Docment对象。
2 DOM4J中的类结构
在DOM4J中,也有Node、Document、Element等接口,结构上与DOM中的接口比较相似。但还是有很多的区别:
在DOM4J中,所有XML组成部分都是一个Node,其中Branch表示可以包含子节点的节点,例如Document和Element都是可以有子节点的,它们都是Branch的子接口。
Attribute是属性节点,CharacterData是文本节点,文本节点有三个子接口,分别是CDATA、Text、Comment。
3 DOM4J获取Document对象
使用DOM4J来加载XML文档,需要先获取SAXReader对象,然后通过SAXReader对象的read()方法来加载XML文档:
SAXReader reader = new SAXReader(); // reader.setValidation(true); Document doc = reader.read("src/students.xml"); |
4 DOM4J保存Document对象
保存Document对象需要使用XMLWriter对象的write()方法来完成,在创建XMLWriter时还可以为其指定XML文档的格式(缩进字符串以及是否换行),这需要使用OutputFormat来指定。
doc.addDocType("students", "", "students.dtd"); OutputFormat format = new OutputFormat("\t", true); format.setEncoding("UTF-8"); XMLWriter writer = new XMLWriter(new FileWriter(xmlName), format); writer.write(doc); writer.close(); |
5 DOM4J创建Document对象
DocumentHelper类有很多的createXXX()方法,用来创建各种Node对象。
Document doc = DocumentHelper.createDocument(); |
Document操作 (*****)
1 遍历students.xml
涉及的相关方法:
l Element getRootElement():Document的方法,用来获取根元素;
l List elements():Element的方法,用来获取所有子元素;
l String attributeValue(String name):Element的方法,用来获取指定名字的属性值;
l Element element(String name):Element的方法,用来获取第一个指定名字的子元素;
l Element elementText(String name):Element的方法,用来获取第一个指定名字的子元素的文本内容。
分析步骤:
l 获取Document对象;
l 获取root元素;
l 获取root所有子元素
l 遍历每个student元素;
- 打印student元素number属性;
- 打印student元素的name子元素内容;
- 打印student元素的age子元素内容;
- 打印student元素的sex子元素内容。
2 给学生元素添加<score>子元素
涉及的相关方法:
l Element addElement(String name):Element的方法,为当前元素添加指定名字子元素。返回值为新建元素对象;
l setText(String text):Element的方法,为当前元素设置文本内容。
分析步骤:
l 获取Document对象;
l 获取root对象;
l 获取root所有子元素;
l 遍历所有学生子元素;
- 创建<score>元素,为<score>添加文本内容;
- 把<score>元素添加到学生元素中。
l 保存Document对象。
3 为张三添加friend属性,指定为李四学号
涉及方法:
l addAttribute(String name, String value):Element的方法,为当前元素添加属性。
分析步骤:
l 获取Document对象;
l 获取root对象;
l 获取root所有子元素;
l 创建两个Element引用:zhangSanEle、liSiEle,赋值为null;
l 遍历所有学生子元素;
- 如果zhangSanEle和liSiEle都不是null,break;
- 判断当前学生元素的name子元素文本内容是zhangSan,那么把当前学生元素赋给zhangSanEle;
- 判断当前学生元素的name子元素文本内容是liSi,那么把当前学生元素赋给liSiEle。
l 判断zhangSanEle和liSiEle都不为null时:
- 获取liSiEle的number属性。
- 为zhangSanEle添加friend属性,属性值为liSi的number属性值。
- 保存Document对象。
4 删除number为ID_1003的学生元素
涉及方法:
l boolean remove(Element e):Element和Document的方法,移除指定子元素;
l Element getParent():获取父元素,根元素的父元素为null。
分析步骤:
l 获取Document对象;
l 获取root对象;
l 获取root所有子元素;
l 遍历所有学生子元素;
- 判断当前学生元素的number属性是否为ID_1003;
² 获取当前元素的父元素;
² 父元素中删除当前元素;
l 保存Document对象.
5 通过List<Student>生成Document并保存
涉及方法:
l DocumentHelper.createDocument():创建Document对象;
l DocumentHelper.createElement(String name):创建指定名称的Element元素。
分析步骤:
l 创建Document对象;
l 为Document添加根元素<students>;
l 循环遍历学生集合List<Student>;
- 把当前学生对象转换成Element元素;
- 把Element元素添加到根元素中;
l 保存Document对象。
把学生转换成Element步骤分析:
l 创建Element对象;
l 为Element添加number属性,值为学生的number;
l 为Element添加name子元素,文本内容为学生的name;
l 为Element添加age子元素,文本内容为学生的age;
l 为Element添加sex子元素,文本内容为学生的sex。
6 新建赵六学生元素,插入到李四之前
涉及方法:
l int indexOf(Node node):Branch的方法,查找指定节点,在当前Branch的子节点集合中的下标位置。
分析步骤:
l 创建赵六学生对象;
l 通过学生对象创建赵六学生元素;
l 通过名称查找李四元素;
l 查看李四元素在其父元素中的位置;
l 获取学生子元素List;
l 将赵六元素插入到List中。
通过名字查找元素:
l 获取Document;
l 获取根元素;
l 获取所有学生元素;
l 遍历学生元素;
- 获取学生元素name子元素的文本内容,与指定名称比较;
² 返回当前学生元素。
7 其它方法介绍
Node方法:
l String asXML():把当前节点转换成字符串,如果当前Node是Document,那么就会把整个XML文档返回;
l String getName():获取当前节点名字;Document的名字就是绑定的XML文档的路径;Element的名字就是元素名称;Attribute的名字就是属性名;
l Document getDocument():返回当前节点所在的Document对象;
l short getNodeType():获取当前节点的类型;
l String getNodeTypeName():获取当前节点的类型名称,例如当前节点是Document的话,那么该方法返回Document;
l String getStringValue():获取当前节点的子孙节点中所有文本内容连接成的字符串;
l String getText():获取当前节点的文本内容。如果当前节点是Text等文本节点,那么本方法返回文本内容;例如当前节点是Element,那么当前节点的内容不是子元素,而是纯文本内容,那么返回文本内容,否则返回空字符串;
l void setDocument(Document doc):给当前节点设置文档元素;
l void setParent(Element parent):给当前节点设置父元素;
l void setText(String text):给当前节点设置文本内容;
Branch方法:
l void add(Element e):添加子元素;
l void add(Node node):添加子节点;
l void add(Comment comment):添加注释;
l Element addElement(String eleName):通过名字添加子元素,返回值为子元素对象;
l void clearContent():清空所有子内容;
l List content():获取所有子内容,与获取所有子元素的区别是,<name>liSi</name>元素没有子元素,但有子内容;
l Element elementById(String id):如果元素有名为“ID”的属性,那么可以使用这个方法来查找;
l int indexOf(Node node):查找子节点在子节点列表中的下标位置;
l Node node(int index):通过下标获取子节点;
l int nodeCount():获取子节点的个数;
l Iterator nodeIterator():获取子节点列表的迭代器对象;
l boolean remove(Node node):移除指定子节点;
l boolean remove(Commont commont):移除指定注释;
l boolean remove(Element e):移除指定子元素;
l void setContent(List content) :设置子节点内容;
Document方法:
l Element getRootElement():获取根元素;
l void setRootElement():设置根元素;
l String getXmlEncoding():获取XML文档的编码;
l void setXmlEncoding():设置XML文档的编码;
Element方法:
l void add(Attribute attr):添加属性节点;
l void add(CDATA cdata):添加CDATA段节点;
l void add(Text Text):添加Text节点;
l Element addAttribute(String name, String value):添加属性,返回值为当前元素本身;
l Element addCDATA(String cdata):添加CDATA段节点;
l Element addComment(String comment):添加属性节点;
l Element addText(String text):添加Text节点;
l void appendAttributes(Element e):把参数元素e的所有属性添加到当前元素中;
l Attribute attribute(int index):获取指定下标位置上的属性对象;
l Attribute attribute(String name):通过指定属性名称获取属性对象;
l int attributeCount():获取属性个数;
l Iterator attributeIterator():获取当前元素属性集合的迭代器;
l List attributes():获取当前元素的属性集合;
l String attributeValue(String name):获取当前元素指定名称的属性值;
l Element createCopy():clone当前元素对象,但不会copy父元素。也就是说新元素没有父元素,但有子元素;
l Element element(String name):获取当前元素第一个名称为name的子元素;
l Iterator elementIterator():获取当前元素的子元素集合的迭代器;
l Iterator elementIterator(String name):获取当前元素中指定名称的子元素集合的迭代器;
l List elements():获取当前元素子元素集合;
l List elements(String name):获取当前元素指定名称的子元素集合;
l String elementText(String name):获取当前元素指定名称的第一个元素文件内容;
l String elementTextTrime(String name):同上,只是去除了无用空白;
l boolean isTextOnly():当前元素是否为纯文本内容元素;
l boolean remove(Attribute attr):移除属性;
l boolean remove(CDATA cdata):移除CDATA;
l boolean remove(Text text):移除Text。
DocumentHelper静态方法介绍:
l static Document createDocument():创建Dcoument对象;
l static Element createElement(String name):创建指定名称的元素对象;
l static Attribute createAttrbute(Element owner, String name, String value):创建属性对象;
l static Text createText(String text):创建属性对象;
l static Document parseText(String text):通过给定的字符串生成Document对象;
Schema
Schema概述
我们学习Schema的第一目标是:参照Schema的要求可以编写XML文档;
第二目标是:可以自己来定义Schema文档。
1 Schema是什么
XML文档的约束,用来替代DTD。
DTD文档不是XML语法,而Schema本身也是XML文档,这对解析器来说不用再去处理非XML的文档了;
DTD只能表述平台线束,而Schema本身也是XML,所以可以描述结构化的约束信息。
DTD不只约束元素或属性的类型,但Schema可以。例如让age属性的取值在0~100之间。
Schema文档的扩展名为xsd,即XML Schema Definition。
2 为students.xml编写DTD
<!ELEMENT students (student+)> <!ELEMENT student (name,age,sex)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT sex (#PCDATA)> <!ATTLIST student number CDATA #REQUIRED> |
3 为students.xml编写schema
<?xml version="1.0"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="students" type="studentsType"/> <xsd:complexType name="studentsType"> <xsd:sequence> <xsd:element name="student" type="studentType" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="studentType"> <xsd:sequence> <xsd:element name="name" type="xsd:string"/> <xsd:element name="age"> <xsd:simpleType> <xsd:restriction base="xsd:integer"> <xsd:maxInclusive value="100"/> <xsd:minInclusive value="0"/> </xsd:restriction> </xsd:simpleType> </xsd:element> <xsd:element name="sex"> <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:enumeration value="男"/> <xsd:enumeration value="女"/> </xsd:restriction> </xsd:simpleType> </xsd:element> </xsd:sequence> <xsd:attribute name="number" type="xsd:string"/> </xsd:complexType> </xsd:schema> |
参照Schema编写XML文档
我们参照上面的Schema文档编写一个studens.xml文件
<?xml version="1.0" encoding="utf-8" standalone="no" ?> |
名称空间相关内容
XSD文档中是创建元素和属性的地方;
XML文档中是使用元素和属性的地方。
所以在XML文档中需要说明使用了哪些XSD文档。
1 什么是名称空间
名称空间是用来处理XML元素或属性的名字冲突问题。你可以理解为Java中的包!包的作用就是用来处理类的名字冲突问题。
注意:XML与Java有很大区别,虽然都是处理名字冲突问题,但语法上是有很大区别的。例如在Java中可以使用import来导入类,但你一定要保存你导入的类已经在类路径(classpath)中存在。使用package为当前Java文件中所有类声明名。但XML的名称空间要比Java复杂很多。
我们在下面讲解XML名称空间时,会使用Java包的概念来理解XML的名称空间的概念,所以现在大家就要注意这么几个特性:
l import:导包,声明名称空间;
l package:定义包,指定目标名称空间;
l classpath:添加到类路径,关联XSD文件
2 声明名称空间(导包)
无论是在XML中,还是在XSD中,都需要声明名称空间。这与Java中使用import来导包是一个道理。当然,前提是有包(创建类是使用了package)才可以导,没包就不能导了。如果被定义的元素在声明时没有指定目标名称空间,那么就是在无名称空间中,那么我们在使用这些在无名称空间中的元素时,就不用再去声明名称空间了。
声明名称空间使用xmlns,例如:xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"。这表示声明了一个名称空间,相当与Java中的import。但是,Java中的import的含义是在下面使用的类,如果没有给出包名,那么就是import导入的这个类。而xmlns表示,下面使用xsi为前缀的元素或属性,都是来自http://www.w3.org/2001/XMLSchema-instance名称空间。也就是说给名称空间起了一个简称,这就相当于我们称呼“北京传智播客教育科技有限公司”为“传智”一样。“传智”就是简称。
例如在XSD文件中,xmlns:xsd="http://www.w3.org/2001/XMLSchema"就是声明名称空间,而这个名称空间是W3C的名称空间,无需关联文件就可以直接声明!在XSD文件中所有使用xsd为前面的元素和属性都是来自http://www.w3.org/2001/XMLSchema名称空间。
名称空间命名:一般名称空间都是以公司的URL来命名,即网址!当然也可以给名称空间命名为aa、bb之类的名字,但这可能会导致名称空间的重名问题。
前缀命名:前缀的命名没有什么要求,但一般对http://www.w3.org/2001/XMLSchema名称空间的前缀都是使用xs或xsd。http://www.w3.org/2001/XMLSchema-instance的前缀使用xsi。
在XML文档中声明xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"名称空间的目的是使用xsi中的一个属性:xsi:noNamespaceSchemaLocation,它是用W3C提供的库属性,用来关联XSD文件用的。当然,它只能关联那些没有“目标名称空间”的XSD文件。下面会讲解目标名称空间!
3 默认名称空间
所谓默认名称空间就是在声明名称空间时,不指定前缀,也可以理解为前缀为空字符串的意思。这样定义元素时,如果没有指定前缀的元素都是在使用默认名称空间中的元素。
xmlns=”http://www.itcast.cn”
当在文档中使用<xxx>时,那么<xxx>元素就是http://www.itcast.cn名称空间中声明的元素。
注意:没有指定前缀的属性不表示在默认名称空间中,而是表示没有名称空间。也就是说,默认名称空间不会涉及到属性,只对元素有效!
XPath(扩展)
XPath概述
1 什么是XPath
XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力。起初 XPath 的提出的初衷是将其作为一个通用的、介于XPointer与XSL间的语法模型。但是 XPath 很快的被开发者采用来当作小型查询语言。
2 DOM4J对XPath的支持
在DOM4J中,Node接口中的三个方法最为常用:
l List selectNodes(String xpathExpression):在当前节点中查找满足XPath表达式的所有子节点;
l Node selectSingleNode(String xpathExpression):在当前节点中查找满足XPath表达式的第一个子节点;
l String valueOf(String xpathExpression):在当前节点中查找满足XPath表达式的第一个子节点的文本内容;