java 中解析xml的技術

最初,XML 語言僅僅是意圖用來做爲 HTML 語言的替代品而出現的,可是隨着該語言的不斷髮展和完善,人們愈來愈發現它所具備的優勢:例如標記語言可擴展,嚴格的語法規定,可以使用有意義的標記,內容存儲和表現分離等等優點註定了該語言從誕生之日起就會走向輝煌。 XML 語言在成爲 W3C 標準以後進入到了一個快速發展的時期,固然它自己所具備的一系列優勢和優點也註定了各大技術廠商對它的偏心,Java 做爲軟件行業的一種開發技術也迅速做出了反應,出現了多種對 XML 支持的工具,本文將會從這個角度對 Java 處理 XML 的幾種主流技術進行介紹,但願能對您有所幫助。在這篇文章中,您將會獲得如下信息:java

  1. Java 提供了哪些優秀的類庫及工具便於程序員對 XML 進行處理 ?
  2. 有了 DOM 了,其它工具類庫還有必要麼 ?
  3. 幾個小例程帶你快速瞭解這三種解析方式

Java 有哪些優秀的類庫及工具便於程序員對 XML 進行處理 ?node

  • 大名鼎鼎的 DOM
  • 綠色環保的 SAX
  • 默默無聞的 Digester

XML 三種解析方式簡介

大名鼎鼎的 DOM程序員

說它大名鼎鼎但是一點不爲過,DOM 是 W3C 處理 XML 的標準 API,它是許多其它與 XML 處理相關的標準的基礎,不只是 Java,其它諸如 Javascript,PHP,MS .NET 等等語言都實現了該標準, 成爲了應用最爲普遍的 XML 處理方式。固然,爲了能提供更多更增強大的功能,Java 對於 DOM 直接擴展工具類有不少,好比不少 Java 程序員耳熟能詳的 JDOM,DOM4J 等等, 它們基本上屬於對 DOM 接口功能的擴充,保留了不少 DOM API 的特性,許多本來的 DOM 程序員甚至都沒有任何障礙就熟練掌握了另外二者的使用,直觀、易於操做的方式使它深受廣大 Java 程序員的喜好。apache

綠色環保的 SAX編程

SAX 的應運而生有它特殊的須要,爲何說它綠色環保呢,這是由於 SAX 使用了最少的系統資源和最快速的解析方式對 XML 處理提供了支持。 但隨之而來繁瑣的查找方式也給廣大程序員帶來許多困擾,經常使人頭痛不已,同時它對 XPath 查詢功能的支持,使人們對它又愛又恨。框架

默默無聞的 Digester:XML 的 JavaBean 化dom

Digester 是 apache 基金組織下的一個開源項目,筆者對它的瞭解源於對 Struts 框架的研究,是否有不少程序員想要一解各大開源框架的設計甚至想要本身寫一個功能強大的框架時會碰到這樣一個難題: 這些形形色色的用 XML 語言標記的框架配置文件,框架底層是用什麼技術來解析呢? DOM 解析耗費時間,SAX 解析又過於繁瑣,何況每次解析系統開銷也會過大, 因而,你們想到須要用與 XML 結構相對應的 JavaBean 來裝載這些信息,由此 Digester 應運而生。它的出現爲 XML 轉換爲 JavaBean 對象的需求帶來了方便的操做接口,使得更多的相似需求獲得了比較完美的解決方法, 再也不須要程序員本身實現此類繁瑣的解析程序了。與此同時 SUN 也推出了 XML 和 JavaBean 轉換工具類 JAXB,有興趣的讀者能夠自行了解。編程語言

 

三種解析方式比較

DOM工具

優缺點:實現 W3C 標準,有多種編程語言支持這種解析方式,而且這種方法自己操做上簡單快捷,十分易於初學者掌握。其處理方式是將 XML 整個做爲相似樹結構的方式讀入內存中以便操做及解析,所以支持應用程序對 XML 數據的內容和結構進行修改,可是同時因爲其須要在處理開始時將整個 XML 文件讀入到內存中去進行分析,所以其在解析大數據量的 XML 文件時會遇到相似於內存泄露以及程序崩潰的風險,請對這點多加註意。

適用範圍:小型 XML 文件解析、須要全解析或者大部分解析 XML、須要修改 XML 樹內容以生成本身的對象模型

SAX

SAX 從根本上解決了 DOM 在解析 XML 文檔時產生的佔用大量資源的問題。其實現是經過相似於流解析的技術,通讀整個 XML 文檔樹,經過事件處理器來響應程序員對於 XML 數據解析的需求。因爲其不須要將整個 XML 文檔讀入內存當中,它對系統資源的節省是十分顯而易見的,它在一些須要處理大型 XML 文檔以及性能要求較高的場合有起了十分重要的做用。支持 XPath 查詢的 SAX 使得開發人員更加靈活,處理起 XML 來更加的駕輕就熟。可是同時,其仍然有一些不足之處也困擾廣大的開發人員:首先是它十分複雜的 API 接口使人望而生畏,其次因爲其是屬於相似流解析的文件掃描方式,所以不支持應用程序對於 XML 樹內容結構等的修改,可能會有不便之處。

適用範圍:大型 XML 文件解析、只須要部分解析或者只想取得部分 XML 樹內容、有 XPath 查詢需求、有本身生成特定 XML 樹對象模型的需求

Digester/JAXB

優缺點 : 因爲其是在上述二者的基礎上衍生出來的工具類,爲的是知足將 XML 轉換爲 JavaBean 的特殊需求,故而沒有什麼特別明顯的優缺點。做爲大名鼎鼎的開源框架 Struts 的 XML 解析工具 Digester,爲咱們帶來了將 XML 轉換爲 JavaBean 的可靠方法。

適用範圍 : 有將 XML 文檔直接轉換爲 JavaBean 需求。

 

應用示例

下面給出一段用於解析的 XML 片斷:

清單 1. XML 片斷
 <?xml version="1.0" encoding="UTF-8"?> 
 <books> 
   <book id="001"> 
      <title>Harry Potter</title> 
      <author>J K. Rowling</author> 
   </book> 
   <book id="002"> 
      <title>Learning XML</title> 
      <author>Erik T. Ray</author> 
   </book> 
 </books>

DOM 解析 XML

Java 中的 DOM 接口簡介: JDK 中的 DOM API 遵循 W3C DOM 規範,其中 org.w3c.dom 包提供了 Document、DocumentType、Node、NodeList、Element 等接口, 這些接口均是訪問 DOM 文檔所必須的。咱們能夠利用這些接口建立、遍歷、修改 DOM 文檔。

javax.xml.parsers 包中的 DoumentBuilder 和 DocumentBuilderFactory 用於解析 XML 文檔生成對應的 DOM Document 對象。

javax.xml.transform.dom 和 javax.xml.transform.stream 包中 DOMSource 類和 StreamSource 類,用於將更新後的 DOM 文檔寫入 XML 文件。

下面給出一個運用 DOM 解析 XML 的例子:

清單 2. DOM 解析 XML
 import java.io.File; 
 import java.io.IOException; 
 import javax.xml.parsers.DocumentBuilder; 
 import javax.xml.parsers.DocumentBuilderFactory; 
 import javax.xml.parsers.ParserConfigurationException; 
 import org.w3c.dom.Document; 
 import org.w3c.dom.Element; 
 import org.w3c.dom.Node; 
 import org.w3c.dom.NodeList; 
 import org.xml.sax.SAXException; 

 public class DOMParser { 
   DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); 
   //Load and parse XML file into DOM 
   public Document parse(String filePath) { 
      Document document = null; 
      try { 
         //DOM parser instance 
         DocumentBuilder builder = builderFactory.newDocumentBuilder(); 
         //parse an XML file into a DOM tree 
         document = builder.parse(new File(filePath)); 
      } catch (ParserConfigurationException e) { 
         e.printStackTrace();  
      } catch (SAXException e) { 
         e.printStackTrace(); 
      } catch (IOException e) { 
         e.printStackTrace(); 
      } 
      return document; 
   } 
	
   public static void main(String[] args) { 
         DOMParser parser = new DOMParser(); 
         Document document = parser.parse("books.xml"); 
         //get root element 
         Element rootElement = document.getDocumentElement(); 

         //traverse child elements 
         NodeList nodes = rootElement.getChildNodes(); 
         for (int i=0; i < nodes.getLength(); i++) 
         { 
            Node node = nodes.item(i); 
            if (node.getNodeType() == Node.ELEMENT_NODE) {   
               Element child = (Element) node; 
               //process child element 
            } 
         } 

         NodeList nodeList = rootElement.getElementsByTagName("book"); 
         if(nodeList != null) 
         { 
            for (int i = 0 ; i < nodeList.getLength(); i++) 
            { 
               Element element = (Element)nodeList.item(i); 
               String id = element.getAttribute("id"); 
            } 
         } 
   } 
 }

在上面的例子中,DOMParser 的 Parse() 方法負責解析 XML 文件並生成對應的 DOM Document 對象。其中 DocumentBuilderFactory 用於生成 DOM 文檔解析器以便解析 XML 文檔。 在獲取了 XML 文件對應的 Document 對象以後,咱們能夠調用一系列的 API 方便的對文檔對象模型中的元素進行訪問和處理。 須要注意的是調用 Element 對象的 getChildNodes() 方法時將返回其下全部的子節點,其中包括空白節點,所以須要在處理子 Element 以前對節點類型加以判斷。

能夠看出 DOM 解析 XML 易於開發,只須要經過解析器創建起 XML 對應的 DOM 樹型結構後即可以方便的使用 API 對節點進行訪問和處理,支持節點的刪除和修改等。 可是 DOM 解析 XML 文件時會將整個 XML 文件的內容解析成樹型結構存放在內存中,所以不適合用 DOM 解析很大的 XML 文件。

SAX 解析 XML

與 DOM 創建樹形結構的方式不一樣,SAX 採用事件模型來解析 XML 文檔,是解析 XML 文檔的一種更快速、更輕量的方法。 利用 SAX 能夠對 XML 文檔進行有選擇的解析和訪問,而沒必要像 DOM 那樣加載整個文檔,所以它對內存的要求較低。 但 SAX 對 XML 文檔的解析爲一次性讀取,不建立任何文檔對象,很難同時訪問文檔中的多處數據。

下面是一個 SAX 解析 XML 的例子:

清單 3. SAX 解析 XML
 import org.xml.sax.Attributes; 
 import org.xml.sax.SAXException; 
 import org.xml.sax.XMLReader; 
 import org.xml.sax.helpers.DefaultHandler; 
 import org.xml.sax.helpers.XMLReaderFactory; 

 public class SAXParser { 

   class BookHandler extends DefaultHandler { 
      private List<String> nameList; 
      private boolean title = false; 
   
      public List<String> getNameList() { 
         return nameList; 
      } 
      // Called at start of an XML document 
      @Override 
      public void startDocument() throws SAXException { 
         System.out.println("Start parsing document..."); 
         nameList = new ArrayList<String>(); 
      } 
      // Called at end of an XML document 
      @Override 
      public void endDocument() throws SAXException {  
         System.out.println("End");  
      } 
      
      /** 
       * Start processing of an element. 
       * @param namespaceURI  Namespace URI 
       * @param localName  The local name, without prefix 
       * @param qName  The qualified name, with prefix 
       * @param atts  The attributes of the element 
       */ 
      @Override 
      public void startElement(String uri, String localName, String qName, 
	     Attributes atts) throws SAXException { 
         // Using qualified name because we are not using xmlns prefixes here. 
         if (qName.equals("title")) { 
            title = true; 
         } 
      } 
   
      @Override 
      public void endElement(String namespaceURI, String localName, String qName) 
         throws SAXException { 
         // End of processing current element 
         if (title) { 
            title = false; 
         } 
      } 
   			
      @Override 
      public void characters(char[] ch, int start, int length) { 
         // Processing character data inside an element 
         if (title) { 
            String bookTitle = new String(ch, start, length); 
            System.out.println("Book title: " + bookTitle); 
            nameList.add(bookTitle); 
         } 
      } 
			
   } 
	
   public static void main(String[] args) throws SAXException, IOException { 
      XMLReader parser = XMLReaderFactory.createXMLReader(); 
      BookHandler bookHandler = (new SAXParser()).new BookHandler(); 
      parser.setContentHandler(bookHandler); 
      parser.parse("books.xml"); 
      System.out.println(bookHandler.getNameList()); 
   } 
 }

SAX 解析器接口和事件處理器接口定義在 org.xml.sax 包中。主要的接口包括 ContentHandler、DTDHandler、EntityResolver 及 ErrorHandler。 其中 ContentHandler 是主要的處理器接口,用於處理基本的文檔解析事件;DTDHandler 和 EntityResolver 接口用於處理與 DTD 驗證和實體解析相關的事件; ErrorHandler 是基本的錯誤處理接口。DefaultHandler 類實現了上述四個事件處理接口。上面的例子中 BookHandler 繼承了 DefaultHandler 類, 並覆蓋了其中的五個回調方法 startDocument()、endDocument()、startElement()、endElement() 及 characters() 以加入本身的事件處理邏輯。

Digester 解析 XML

爲了知足將 XML 轉換爲 JavaBean 的特殊需求,Apache 旗下的一個名爲 Digester 的工具爲咱們提供了這麼一個選擇。因爲最終是將 XML 轉化爲 JavaBean 存儲在內存當中, 故而解析性能等方面其實與使用者並無多大關係。解析的關鍵在於用以匹配 XML 的模式以及規則等,因爲該工具較爲複雜,限於篇幅,做者只能給予簡單的介紹。

下面是一個 Digester 解析 XML 的例子片斷:

清單 4. Digester 解析 XML
 // 定義要解析的 XML 的路徑,並初始化工具類
 File input = new File("books.xml"); 
 Digester digester = new Digester(); 

 // 若是碰到了 <books> 這個標籤,應該初始化 test.myBean.Books 這個 JavaBean 並填裝相關內容
 digester.addObjectCreate("books", "test.myBean.Books"); 
 digester.addSetProperties("books"); 
 // 若是碰到了 <books/book> 這個標籤,同上初始化 test.myBean.Book 這個 JavaBean 
 digester.addObjectCreate("books/book", "test.myBean.Book"); 
 digester.addSetProperties("books/book"); 
 // 經過調用上面已經初始化過的 JavaBean 的 addBook() 方法來把多個 <books/book> 加到一個集合中
 digester.addSetNext("books/book", "addBook", "test.myBean.Book"); 

 // 定義好了上面的解析規則後,就能夠開始進行解析工做了
 Books books = (Books) digester.parse(input);

上述代碼簡單的向讀者展現了 Digester 處理 XML 的一些要點,主要是說明了一些模式以及規則的匹配。 簡言之,Digester 就是一種用來把一個 XML 轉化爲一個與該 XML 結構相似的 JavaBean。你能夠把 XML 根元素想象成一個 JavaBean, 該根元素的 attribute 就是這個 JavaBean 的各類 Field,當該根元素有其餘子 tag 時,又要把這個子 tag 想象成一個個新的 XML,將其視爲一個新的 JavaBean, 並做爲一個 Field 加入到父 Bean 當中,而後以此類推,經過循環的方式將整個 XML 進行解析。

相關文章
相關標籤/搜索