Dom4j工具
使用步骤:
1)导入dom4j的核心包。 dom4j-1.6.1.jar(点击下载)
2)编写Dom4j读取xml文件代码
相关方法
节点:
Iterator Element.nodeIterator(); //获取当前标签节点下的所有子节点
标签:
Element Document.getRootElement(); //获取xml文档的根标签
Element ELement.element("标签名") //指定名称的第一个子标签
Iterator<Element> Element.elementIterator("标签名");// 指定名称的所有子标签
List<Element> Element.elements(); //获取所有子标签
属性:
String Element.attributeValue("属性名") //获取指定名称的属性值
Attribute Element.attribute("属性名");//获取指定名称的属性对象
Attribute.getName() //获取属性名称
Attibute.getValue() //获取属性值
List<Attribute> Element.attributes(); //获取所有属性对象
Iterator<Attribute> Element.attibuteIterator(); //获取所有属性对象
文本:
Element.getText(); //获取当前标签的文本
Element.elementText("标签名") //获取当前标签的指定名称的子标签的文本内容
Dom4j修改xml文档
(1)写出内容到xml文档
XMLWriter writer = new XMLWriter(OutputStream, OutputForamt)
wirter.write(Document);
(2)常用方法
增加
Ø DocumentHelper.createDocument(); 增加文档
Ø addElement(名称) 增加标签
Ø addAttribute(名称,值) 增加属性
修改
Ø Attribute.setValue(值)
Ø Element.addAttribute(属性名,值)
Ø Element.setText(内容)
删除
Ø Element.detach()
Ø Attribute.detach()
SAX解析工具
核心的API:
SAXParser类: 用于读取和解析xml文件对象
parse(File f,
DefaultHandler dh
)方法: 参数一: File:表示 读取的xml文件。
参数二: DefaultHandler: SAX事件处理程序。使用DefaultHandler的子类[一个类继承class 类名(extends DefaultHandler) 在调用是创建传进去
例如:
1
2
3
4
5
6
|
//创建SAXParser对象
SAXParser parser=SAXParserFactory.newInstance().newSAXParser();
//调用parse方法
parser.parse(
new
File(
"./src/contact.xml"
),
new
MyDefaultHandler());
|
DefaultHandler类的API:
void startDocument() : 在读到文档开始时调用
void endDocument() :在读到文档结束时调用
void startElement(String uri, String localName, String qName, Attributes attributes) :读到开始标签时调用
void endElement(String uri, String localName, String qName) :读到结束标签时调用
void characters(char[] ch, int start, int length) : 读到文本内容时调用
比较两者之间的区别
DOM解析 | SAX解析 |
原理: 一次性加载xml文档,不适合大容量的文件读取 | 原理: 加载一点,读取一点,处理一点。适合大容量文件的读取 |
DOM解析可以任意进行增删改成 | SAX解析只能读取 |
DOM解析任意读取任何位置的数据,甚至往回读 | SAX解析只能从上往下,按顺序读取,不能往回读 |
DOM解析面向对象的编程方法(Node,Element,Attribute),Java开发者编码比较简单。 | SAX解析基于事件的编程方法。java开发编码相对复杂。 |
xPath技术
(1)xPath的作用: 主要是用于快速获取所需的节点对象 ( 在dom4j中如何使用xPath技术)
(2)步骤及方法
导入xPath支持jar包 。 jaxen-1.1-beta-6.jar(点击下载)
使用xpath方法
List<Node> selectNodes("xpath表达式"); 查询多个节点对象
Node selectSingleNode("xpath表达式"); 查询一个节点对象
(3)xPath语法
/ 绝对路径 表示从xml的根位置开始或子元素(一个层次结构)
// 相对路径 表示不分任何层次结构的选择元素。
* 通配符 表示匹配所有元素
[] 条件 表示选择什么条件下的元素
@ 属性 表示选择属性节点 //BBB[@name='bbb'] 选择含有属性name且其值为'bbb'的BBB元素
and 关系 表示条件的与关系(等价于&&)
text() 文本 表示选择文本内容
实例练习
创建一个通讯录,有联系人的各种信息,在控制台有一些功能,及具体实现效果如图
对应生成的xml文件
首先,分解下一下,既然是一个联系人,有众多属性,我们可以考略通过创建一个Contact类同时将其封装,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
package
com.gqx.Test;
public
class
Contact {
private
String Id;
private
String name;
private
String sex;
private
String age;
private
String phone;
private
String qq;
private
String email;
public
String getId() {
return
Id;
}
public
void
setId(String id) {
Id = id;
}
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
public
String getSex() {
return
sex;
}
public
void
setSex(String sex) {
this
.sex = sex;
}
public
String getAge() {
return
age;
}
public
void
setAge(String age) {
this
.age = age;
}
public
String getPhone() {
return
phone;
}
public
void
setPhone(String phone) {
this
.phone = phone;
}
public
String getQq() {
return
qq;
}
public
void
setQq(String qq) {
this
.qq = qq;
}
public
String getEmail() {
return
email;
}
public
void
setEmail(String email) {
this
.email = email;
}
@Override
public
String toString() {
return
"Contact [Id="
+ Id +
", name="
+ name +
", sex="
+ sex
+
", age="
+ age +
", phone="
+ phone +
", qq="
+ qq
+
", email="
+ email +
"]"
;
}
}
|
其次考略到改程序额主菜单这些目录实现的操作比较复杂,不能一起堆放在主程序中,这时可以考虑创建一个抽象的接口将目录功能做一个汇总,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package
com.gqx.Test;
import
java.io.FileNotFoundException;
import
java.io.UnsupportedEncodingException;
import
java.util.List;
import
org.dom4j.DocumentException;
public
interface
ContactOperate {
public
void
addContact(Contact contact)
throws
Exception;
public
void
ModifyContact(Contact contact)
throws
Exception;
public
void
removeContact(String id)
throws
Exception;
public
List<Contact> checkContacts();
}
|
这个时候我们就可以写出主程序了,虽然上面接口的具体方法,我们还没有实现,我们先把框架搭好
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
package
com.gqx.Test;
import
java.io.BufferedReader;
import
java.io.IOException;
import
java.io.InputStreamReader;
import
java.util.List;
import
java.util.Scanner;
public
class
Menu {
public
static
void
main(String[] args)
throws
Exception {
// TODO Auto-generated method stub
Scanner bf=
new
Scanner(System.in);
//创建接口,同时对实例化它的实现接口
ContactOperate operator=
new
Operator();
while
(
true
) {
//看到菜单
printMenu();
//读取用户输入
int
command=Integer.parseInt(bf.nextLine());
switch
(command) {
case
1
:
//1、添加联系人
Contact contact=
new
Contact();
System.out.println(
"请输入联系人姓名:"
);
String name=bf.nextLine();
contact.setName(name);
System.out.println(
"请输入联系人ID:"
);
String id=bf.nextLine();
contact.setId(id);
System.out.println(
"请输入联系人性别:"
);
String sex=bf.nextLine();
contact.setSex(sex);
System.out.println(
"请输入联系人年龄:"
);
String age=bf.nextLine();
contact.setAge(age);
System.out.println(
"请输入联系人电话:"
);
String phone=bf.nextLine();
contact.setPhone(phone);
System.out.println(
"请输入联系人邮箱:"
);
String email=bf.nextLine();
contact.setEmail(email);
System.out.println(
"请输入联系人qq:"
);
String qq=bf.nextLine();
contact.setQq(qq);
System.out.println(contact);
operator.addContact(contact);
break
;
case
2
:
Contact contact1=
new
Contact();
System.out.println(
"请输入要修改的联系人ID:"
);
String id1=bf.nextLine();
contact1.setId(id1);
System.out.println(
"请输入修改联系人姓名:"
);
String name1=bf.nextLine();
contact1.setName(name1);
System.out.println(
"请输入修改联系人性别:"
);
String sex1=bf.nextLine();
contact1.setSex(sex1);
System.out.println(
"请输入修改联系人年龄:"
);
String age1=bf.nextLine();
contact1.setAge(age1);
System.out.println(
"请输入修改联系人电话:"
);
String phone1=bf.nextLine();
contact1.setPhone(phone1);
System.out.println(
"请输入修改联系人邮箱:"
);
String email1=bf.nextLine();
contact1.setEmail(email1);
System.out.println(
"请输入修改联系人qq:"
);
String qq1=bf.nextLine();
contact1.setQq(qq1);
operator.ModifyContact(contact1);
break
;
case
3
:
//删除联系人
String idString=bf.nextLine();
operator.removeContact(idString);
operator.removeContact(idString);
break
;
case
4
:
//查看所有联系人
List<Contact> contacts=operator.checkContacts();
for
(Contact contact2 : contacts) {
System.out.println(contact2);
}
break
;
case
5
:
System.out.println(
"你已退出系统!"
);
System.exit(
0
);
break
;
default
:
System.out.println(
"输入错误,请重新输入!!!"
);
break
;
}
}
}
private
static
void
printMenu() {
System.out.println(
"======主菜单======"
);
System.out.println(
"1、添加联系人"
);
System.out.println(
"2、修改联系人"
);
System.out.println(
"3、删除联系人"
);
System.out.println(
"4、查看所有联系人"
);
System.out.println(
"5、退出系统"
);
System.out.println(
"================"
);
}
}
|
到现在我们剩下的工作就是创建一个Operate类来实现该上述接口以完成其具体的功能,但在写的过程中我们注意到喝多代码一直重复着,比如讲一个Document的对象写入本地的xml文档,不管是添加联系人操作还是删除或者修改联系人的操作,这个时候为了提高代码的复用性,我们可以创建以XMLUtil工具类来简化代码,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
package
com.gqx.Test;
import
java.io.FileNotFoundException;
import
java.io.FileOutputStream;
import
java.io.OutputStream;
import
javax.management.RuntimeErrorException;
import
org.dom4j.Document;
import
org.dom4j.DocumentException;
import
org.dom4j.io.OutputFormat;
import
org.dom4j.io.SAXReader;
import
org.dom4j.io.XMLWriter;
/*
* xml操作的工具类
*/
public
class
XMLUtil {
//写出一个xml文件
public
static
void
write2xml(Document doc)
throws
Exception{
OutputStream out=
new
FileOutputStream(
"e:/contact.xml"
);
OutputFormat format=OutputFormat.createPrettyPrint();
format.setEncoding(
"utf-8"
);
XMLWriter writer=
new
XMLWriter(out,format);
writer.write(doc);
writer.close();
}
//读取本地xml文件的方法
public
static
Document getDocument(){
Document doc;
try
{
doc =
new
SAXReader().read(
"e:/contact.xml"
);
return
doc;
}
catch
(DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw
new
RuntimeException(e);
}
}
}
|
完成这个操作后,这个时候可以来完成具体的核心操作了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
package
com.gqx.Test;
import
java.io.File;
import
java.io.FileNotFoundException;
import
java.io.FileOutputStream;
import
java.io.OutputStream;
import
java.io.UnsupportedEncodingException;
import
java.util.ArrayList;
import
java.util.List;
import
org.dom4j.Document;
import
org.dom4j.DocumentException;
import
org.dom4j.DocumentHelper;
import
org.dom4j.Element;
import
org.dom4j.Node;
import
org.dom4j.io.OutputFormat;
import
org.dom4j.io.SAXReader;
import
org.dom4j.io.XMLWriter;
public
class
Operator
implements
ContactOperate {
@Override
public
void
addContact(Contact contact)
throws
Exception {
// TODO Auto-generated method stub
/**
* 添加联系人,把contact保存到xml文档中
*/
File file=
new
File(
"e:/contact.xml"
);
Document doc=
null
;
Element rootElem=
null
;
if
(file.exists()) {
doc=
new
SAXReader().read(file);
rootElem=doc.getRootElement();
}
else
{
//如果没有xml文件,创建xml文件
doc=DocumentHelper.createDocument();
rootElem=doc.addElement(
"contactList"
);
}
//添加contact标签
Element contactElem=rootElem.addElement(
"contact"
);
contactElem.addAttribute(
"id"
, contact.getId());
contactElem.addElement(
"name"
).setText(contact.getName());
contactElem.addElement(
"sex"
).setText(contact.getSex());
contactElem.addElement(
"age"
).setText(contact.getAge());
contactElem.addElement(
"phone"
).setText(contact.getPhone());
contactElem.addElement(
"email"
).setText(contact.getEmail());
contactElem.addElement(
"qq"
).setText(contact.getQq());
/**
* 代码中多处用到将document对象写入xml文档中,
* 此时可以加强代码的复用性,写一个xml的工具类,
* 其中一个方法便是将document转化为xml的静态方法
*/
XMLUtil.write2xml(doc);
}
@Override
public
void
ModifyContact(Contact contact)
throws
Exception {
// TODO Auto-generated method stub
//根据xpath快速找到其属性id为xx的contact
//先读取xml文件
Document doc=
new
SAXReader().read(
"e:/contact.xml"
);
//根据xpath快熟找到该节点
Element contactNode=(Element) doc.selectSingleNode(
"//contact[@id='"
+contact.getId()+
"']"
);
//根据标签该文本
contactNode.element(
"name"
).setText(contact.getName());
contactNode.element(
"age"
).setText(contact.getAge());
contactNode.element(
"email"
).setText(contact.getEmail());
contactNode.element(
"phone"
).setText(contact.getPhone());
contactNode.element(
"sex"
).setText(contact.getSex());
XMLUtil.write2xml(doc);
}
@Override
public
void
removeContact(String id)
throws
Exception {
// TODO Auto-generated method stub
//先读取xml文件
Document doc=XMLUtil.getDocument();
//根据xpath快熟找到该节点
Element contactNode=(Element) doc.selectSingleNode(
"//contact[@id='"
+id+
"']"
);
//删除节点
contactNode.detach();
XMLUtil.write2xml(doc);
}
@Override
public
List<Contact> checkContacts() {
// TODO Auto-generated method stub
Document doc=XMLUtil.getDocument();
//创建list集合
List<Contact> list =
new
ArrayList<Contact>();
List<Element> conList=(List<Element>) doc.selectNodes(
"//contact"
);
for
(Element element : conList) {
Contact contact=
new
Contact();
contact.setId(element.attributeValue(
"id"
));
contact.setAge(element.elementText(
"age"
));
contact.setEmail(element.elementText(
"email"
));
contact.setName(element.elementText(
"name"
));
contact.setPhone(element.elementText(
"phone"
));
contact.setQq(element.elementText(
"qq"
));
contact.setSex(element.elementText(
"sex"
));
list.add(contact);
}
return
list;
}
}
|
注意:有时候在调试以上各种方法的时候,我们可以创建一个调试类,来对每一个具体的操作来调试,可以分别对接口中的每一个方法测试。这样方便发现其中过程是否发生了错误:如
package com.gqx.Test; import java.util.List; import org.junit.Before; public class Test { Operator operator=null; //初始化这个对象的实例 @Before public void init(){ operator=new Operator(); } @org.junit.Test public void AddContact() throws Exception{ Contact contact=new Contact(); contact.setId("002"); contact.setAge("21"); contact.setEmail("454444@qq.com"); contact.setName("gqxing"); contact.setPhone("13455555"); contact.setQq("235346662"); contact.setSex("男"); operator.addContact(contact); } @org.junit.Test public void UpdateContact() throws Exception{ Contact contact=new Contact(); contact.setId("003"); contact.setAge("0"); contact.setEmail("0000000@qq.com"); contact.setName("test"); contact.setPhone("0-00000000000"); contact.setQq("000000000000"); contact.setSex("男"); operator.ModifyContact(contact); } @org.junit.Test public void removeContact() throws Exception{ operator.removeContact("003"); } @org.junit.Test public void allContact() throws Exception{ List<Contact> contacts= operator.checkContacts(); for (Contact contact : contacts) { System.out.println(contact); } } }
写在最后:实现多功能的操作,可以通过接口或者抽象类去理清其中的关系,避免代码臃肿和杂乱,还有junit是一个很好的测试类。