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("[email protected]");
        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("[email protected]");
        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是一個很好的測試類。