XML解析
Posted 张玉宝
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XML解析相关的知识,希望对你有一定的参考价值。
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是一个很好的测试类。
以上是关于XML解析的主要内容,如果未能解决你的问题,请参考以下文章
在Tomcat的安装目录下conf目录下的server.xml文件中增加一个xml代码片段,该代码片段中每个属性的含义与用途