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解析的主要内容,如果未能解决你的问题,请参考以下文章

无法解析片段中的 findViewById [重复]

jsoup解析xml某片段的问题

为 Blogger 上的博客格式化代码片段 [关闭]

java解析xml的几种方式哪种最好?

使用非utf-8编码在Python中解析XML

在Tomcat的安装目录下conf目录下的server.xml文件中增加一个xml代码片段,该代码片段中每个属性的含义与用途