四種xml的解析方式


這篇文章是我上網找資料,加上自己總結了一些而得

資料來源:

http://www.cnblogs.com/allenzheng/archive/2012/12/01/2797196.html

http://www.cnblogs.com/lanxuezaipiao/archive/2013/05/17/3082949.html


其實我覺得這四種解析方式又大致可以分為兩種:一種是基於樹結構處理的Dom解析,另外一種是基於事件模型的SAX解析

一、介紹及優缺點分析

1. DOM(Document Object Model)

      DOM是用與平台和語言無關的方式表示XML文檔的官方W3C標准。DOM是以層次結構組織的節點或信息片斷的集合。這個層次結構允許開發人員在樹中尋找特定信息。分析該結構通常需要加載整個文檔和構造層次結構,然后才能做任何工作。由於它是基於信息層次的,因而DOM被認為是基於樹或基於對象的。

【優點】
      ①允許應用程序對數據和結構做出更改。
      ②訪問是雙向的,可以在任何時候在樹中上下導航,獲取和操作任意部分的數據。
【缺點】
      ①通常需要加載整個XML文檔來構造層次結構,消耗資源大。

xml:

<?xml version="1.0" encoding="UTF-8"?>
<users>
    <user id="0">
        <name>yaobo</name>
        <age>22</age>
        <sex>male</sex>
    </user>
    <user id="1">
        <name>學生</name>
        <age>24</age>
        <sex>Male</sex>
    </user>
    <user id="2">
        <name>wjm</name>
        <age>23</age>
        <sex>male</sex>
    </user>
    <user id="3">
        <name>wh</name>
        <age>24</age>
        <sex>Male</sex>
    </user>
    
    <user >
        <name>yaobo</name>
        <age>12</age>
    </user>
</users>

 

 Dom解析:

package Test1;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Dom {
    
    public void parser(String url){
        DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder db=dbf.newDocumentBuilder();
            Document doc=db.parse(url);
            NodeList users=doc.getChildNodes();
            for(int i=0;i<users.getLength();i++){
                Node user=users.item(i);
                //這次取出的是節點users 
                //System.out.println(user.getNodeName()+users.getLength());
                NodeList userList=user.getChildNodes();
                
                for(int j=0;j<userList.getLength();j++){
                    Node info=userList.item(j);
                    //這次取出的是節點user
                    //System.out.println(info.getNodeName());
                    NodeList attribute=info.getChildNodes();
                    //System.out.println(attribute.item(0).getNodeName()+":"+attribute.item(0).getTextContent());
                    for(int k=0;k<attribute.getLength();k++){
                        if(attribute.item(k).getNodeName() != "#text"){
                            //這次取出的user下面的屬性節點
                            System.out.println(attribute.getLength()+attribute.item(k).getNodeName()+":"+attribute.item(k).getTextContent());
                        }
                    }
                    System.out.println();
                }
                
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
package Test1;

public class Test {

    public static void main(String[] args) {
        String url="src/Test/Jixie.xml";
//        Sax sax=new Sax();
//        sax.parse();
//        
        Dom dom=new Dom();
        dom.parser(url);

    }

}

 

 

   

2. SAX(Simple API for XML)

     SAX處理的優點非常類似於流媒體的優點。分析能夠立即開始,而不是等待所有的數據被處理。而且,由於應用程序只是在讀取數據時檢查數據,因此不需要將數據存儲在內存中。這對於大型文檔來說是個巨大的優點。事實上,應用程序甚至不必解析整個文檔;它可以在某個條件得到滿足時停止解析。一般來說,SAX還比它的替代者DOM快許多。

     選擇DOM還是選擇SAX? 對於需要自己編寫代碼來處理XML文檔的開發人員來說, 選擇DOM還是SAX解析模型是一個非常重要的設計決策。 DOM采用建立樹形結構的方式訪問XML文檔,而SAX采用的是事件模型。

     DOM解析器把XML文檔轉化為一個包含其內容的樹,並可以對樹進行遍歷。用DOM解析模型的優點是編程容易,開發人員只需要調用建樹的指令,然后利用navigation APIs訪問所需的樹節點來完成任務。可以很容易的添加和修改樹中的元素。然而由於使用DOM解析器的時候需要處理整個XML文檔,所以對性能和內存的要求比較高,尤其是遇到很大的XML文件的時候。由於它的遍歷能力,DOM解析器常用於XML文檔需要頻繁的改變的服務中。

     SAX解析器采用了基於事件的模型,它在解析XML文檔的時候可以觸發一系列的事件,當發現給定的tag的時候,它可以激活一個回調方法,告訴該方法制定的標簽已經找到。SAX對內存的要求通常會比較低,因為它讓開發人員自己來決定所要處理的tag.特別是當開發人員只需要處理文檔中所包含的部分數據時,SAX這種擴展能力得到了更好的體現。但用SAX解析器的時候編碼工作會比較困難,而且很難同時訪問同一個文檔中的多處不同數據。

【優勢】
     ①不需要等待所有數據都被處理,分析就能立即開始。
     ②只在讀取數據時檢查數據,不需要保存在內存中。
     ③可以在某個條件得到滿足時停止解析,不必解析整個文檔。
     ④效率和性能較高,能解析大於系統內存的文檔。

【缺點】
     ①需要應用程序自己負責TAG的處理邏輯(例如維護父/子關系等),文檔越復雜程序就越復雜。
     ②單向導航,無法定位文檔層次,很難同時訪問同一文檔的不同部分數據,不支持XPath。

下面結合一張圖來詳細講解Sax解析。


xml文件被Sax解析器載入,由於Sax解析是按照xml文件的順序來解析,當讀入<?xml.....>時,會調用startDocument()方法,當讀入<books>的時候,由於它是個ElementNode,所以會調用startElement(String uri, String localName, String qName, Attributes attributes) 方法,其中第二個參數就是節點的名稱,注意:由於有些環境不一樣,有時候第二個參數有可能為空,所以可以使用第三個參數,因此在解析前,先調用一下看哪個參數能用,第4個參數是這個節點的屬性。這里我們不需要這個節點,所以從<book>這個節點開始,也就是圖中1的位置,當讀入時,調用startElement(....)方法,由於只有一個屬性id,可以通過attributes.getValue(0)來得到,然后在圖中標明2的地方會調用characters(char[] ch, int start, int length)方法,不要以為那里是空白,Sax解析器可不那么認為,Sax解析器會把它認為是一個TextNode。但是這個空白不是我們想要的數據,我們是想要<name>節點下的文本信息。這就要定義一個記錄當上一節點的名稱的TAG,在characters(.....)方法中,判斷當前節點是不是name,是再取值,才能取到thinking in java。

Sax解析:

package Test1;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class Sax {
    public void parse(String url) {
        SAXParserFactory sf= SAXParserFactory.newInstance(); 
        SAXParser sp;
        try {
            sp = sf.newSAXParser();
            MyHander mh=new MyHander("user");
            sp.parse(url, mh);
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }  
}

class MyHander extends DefaultHandler{
    String nodeName;
    
    Map<String,String> map;
    //將所以解析的數據存到list集合中
    List<Map> list;
    
    public MyHander(String nodeName){
        this.nodeName=nodeName;
        list=new ArrayList<Map>();
    }

    //這是 解析到當前節點的名稱
    String tagName;
    
    @Override
    public void startDocument() throws SAXException {
        System.out.println("解析開始:");  
    }
    
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        
        System.out.println("startElement:"+qName);
        //判斷是否為所需節點名
        if(qName==nodeName){
            map=new HashMap<String,String>();
        }
        
        if(attributes!=null && attributes.getLength()>0){
            //這一步是將id的<user id="">中的id值得名稱和屬性存到map中
            map.put(attributes.getQName(0), attributes.getValue(0));
        }
        tagName=qName;
    }
    
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        System.out.println("characters: ");
        if(map!=null && tagName!=null){
            //獲取當前節點的內容
            String content=new String(ch,start,length);
            
            if(content!=null && !content.trim().equals("") && !content.trim().equals("\n")){
                System.out.println("yaobo"+content);
                map.put(tagName, content);
                System.out.println(tagName+" "+content);
            }
            content=null;   
        }
    }
    
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        System.out.println("endElement:"+tagName);
        if(qName.equals(nodeName)){
            list.add(map);
            map=null;
        }
    }

    @Override
    public void endDocument() throws SAXException {
        System.out.println("解析結束");
        System.out.println(list);
    }
    
}
分析:用SAX解析XML采用的是從上而下的基於事件驅動的解析方式,在解析過程中會視情況自動調用startDocument()、startElement()、characters()、endElement()、endDocument()等相關的方法。
下面這幅圖進行了詳細的講解
 
 
      由編譯執行的結果來看:
  • startDocument()方法只會在文檔開始解析的時候被調用,每次解析只會調用一次。
  • startElement()方法每次在開始解析一個元素,即遇到元素標簽開始的時候都會調用。
  • characters()方法也是在每次解析到元素標簽攜帶的內容時都會調用,即使該元素標簽的內容為空或換行。而且如果元素內嵌套元素,在父元素結束標簽前, characters()方法會再次被調用,此處需要注意。
  • endElement()方法每次在結束解析一個元素,即遇到元素標簽結束的時候都會調用。
  • endDocument() startDocument()方法只會在文檔解析結束的時候被調用,每次解析只會調用一次。

 

 3. JDOM(Java-based Document Object Model)

     JDOM的目的是成為Java特定文檔模型,它簡化與XML的交互並且比使用DOM實現更快。由於是第一個Java特定模型,JDOM一直得到大力推廣和促進。正在考慮通過“Java規范請求JSR-102”將它最終用作“Java標准擴展”。從2000年初就已經開始了JDOM開發。

     JDOM與DOM主要有兩方面不同。首先,JDOM僅使用具體類而不使用接口。這在某些方面簡化了API,但是也限制了靈活性。第二,API大量使用了Collections類,簡化了那些已經熟悉這些類的Java開發者的使用。

     JDOM文檔聲明其目的是“使用20%(或更少)的精力解決80%(或更多)Java/XML問題”(根據學習曲線假定為20%)。JDOM對於大多數Java/XML應用程序來說當然是有用的,並且大多數開發者發現API比DOM容易理解得多。JDOM還包括對程序行為的相當廣泛檢查以防止用戶做任何在XML中無意義的事。然而,它仍需要您充分理解XML以便做一些超出基本的工作(或者甚至理解某些情況下的錯誤)。這也許是比學習DOM或JDOM接口都更有意義的工作。

     JDOM自身不包含解析器。它通常使用SAX2解析器來解析和驗證輸入XML文檔(盡管它還可以將以前構造的DOM表示作為輸入)。它包含一些轉換器以將JDOM表示輸出成SAX2事件流、DOM模型或XML文本文檔。JDOM是在Apache許可證變體下發布的開放源碼。

【優點】
     ①使用具體類而不是接口,簡化了DOM的API。
     ②大量使用了Java集合類,方便了Java開發人員。

【缺點】
     ①沒有較好的靈活性。
     ②性能較差。

package Test1;

import java.io.IOException;
import java.util.List;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;


public class JDom {
    public void parserXml(String fileName){
        SAXBuilder sb=new SAXBuilder();
        try {
            Document doc=sb.build(fileName);
            Element users=doc.getRootElement();
            List userList=users.getChildren();
            for(int i=0;i<userList.size();i++){
                Element user=(Element) userList.get(i);
                List content=user.getChildren();
                for(int j=0;j<content.size();j++){
                    System.out.println(((Element) content.get(j)).getName()+":"+((Element) content.get(j)).getValue());
                    }
                System.out.println();
            }
        
        } catch (JDOMException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

4. DOM4J(Document Object Model for Java)
      雖然DOM4J代表了完全獨立的開發結果,但最初,它是JDOM的一種智能分支。它合並了許多超出基本XML文檔表示的功能,包括集成的XPath支持、XML Schema支持以及用於大文檔或流化文檔的基於事件的處理。它還提供了構建文檔表示的選項,它通過DOM4J API和標准DOM接口具有並行訪問功能。從2000下半年開始,它就一直處於開發之中。

      為支持所有這些功能,DOM4J使用接口和抽象基本類方法。DOM4J大量使用了API中的Collections類,但是在許多情況下,它還提供一些替代方法以允許更好的性能或更直接的編碼方法。直接好處是,雖然DOM4J付出了更復雜的API的代價,但是它提供了比JDOM大得多的靈活性。

      在添加靈活性、XPath集成和對大文檔處理的目標時,DOM4J的目標與JDOM是一樣的:針對Java開發者的易用性和直觀操作。它還致力於成為比JDOM更完整的解決方案,實現在本質上處理所有Java/XML問題的目標。在完成該目標時,它比JDOM更少強調防止不正確的應用程序行為。

      DOM4J是一個非常非常優秀的Java XML API,具有性能優異、功能強大和極端易用使用的特點,同時它也是一個開放源代碼的軟件。如今你可以看到越來越多的Java軟件都在使用DOM4J來讀寫XML,特別值得一提的是連Sun的JAXM也在用DOM4J.

【優點】
     ①大量使用了Java集合類,方便Java開發人員,同時提供一些提高性能的替代方法。
     ②支持XPath。
     ③有很好的性能。

【缺點】
     ①大量使用了接口,API較為復雜。

package Test1;

import java.io.File;
import java.util.Iterator;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;


public class Dom4j {
    public void parserXml(String url){
        File inputXml=new File(url);
        SAXReader sr=new SAXReader();
        try {
            Document doc=sr.read(inputXml);
            Element users=(Element) doc.getRootElement();
        
            for(Iterator i=users.elementIterator(); i.hasNext();){
                Element user=(Element) i.next();
                for(Iterator j=user.elementIterator();j.hasNext();){
                    //System.out.println(((Element) j.next()).getName()+":"+((Element) j.next()).getText());
                    Element node = (Element) j.next();
                    System.out.println(node.getName() +":"+node.getText());
                    
                    //這里不能用下面這種寫法來表示,我覺得可能是讀取速度的問題
                   // System.out.println((Element) j.next().getName() + ":" + node.getText());
                    
                }
                System.out.println();
            }
        } catch (DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

二、比較

     1. DOM4J性能最好,連Sun的JAXM也在用DOM4J。目前許多開源項目中大量采用DOM4J,例如大名鼎鼎的Hibernate也用DOM4J來讀取XML配置文件。如果不考慮可移植性,那就采用DOM4J.

     2. JDOM和DOM在性能測試時表現不佳,在測試10M文檔時內存溢出,但可移植。在小文檔情況下還值得考慮使用DOM和JDOM.雖然JDOM的開發者已經說明他們期望在正式發行版前專注性能問題,但是從性能觀點來看,它確實沒有值得推薦之處。另外,DOM仍是一個非常好的選擇。DOM實現廣泛應用於多種編程語言。它還是許多其它與XML相關的標准的基礎,因為它正式獲得W3C推薦(與基於非標准的Java模型相對),所以在某些類型的項目中可能也需要它(如在JavaScript中使用DOM)。

     3. SAX表現較好,這要依賴於它特定的解析方式-事件驅動。一個SAX檢測即將到來的XML流,但並沒有載入到內存(當然當XML流被讀入時,會有部分文檔暫時隱藏在內存中)。

     我的看法:如果XML文檔較大且不考慮移植性問題建議采用DOM4J;如果XML文檔較小則建議采用JDOM;如果需要及時處理而不需要保存數據則考慮SAX。但無論如何,還是那句話:適合自己的才是最好的,如果時間允許,建議大家講這四種方法都嘗試一遍然后選擇一種適合自己的即可。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM