Java 處理 XML的四種方法 -->附:XmlUtils

XML現在已經成爲一種通用的數據交換格式,平臺的無關性使得很多場合都需要用到XML。本文將詳細介紹用Java解析XML的四種方法。
        XML現在已經成爲一種通用的數據交換格式,它的平臺無關性,語言無關性,系統無關性,給數據集成與交互帶來了極大的方便。對於XML本身的語法知識與技術細節,需要閱讀相關的技術文獻,這裏麪包括的內容有DOM(Document Object Model),DTD(Document Type Definition),SAX(Simple API for XML),XSD(Xml Schema Definition),XSLT(Extensible Stylesheet Language Transformations),具體可參閱w3c官方網站文檔http://www.w3.org獲取更多信息。
        XML在不同的語言裏解析方式都是一樣的,只不過實現的語法不同而已。基本的解析方式有兩種,一種叫SAX,另一種叫DOM。SAX是基於事件流的解析,DOM是基於XML文檔樹結構的解析。

        Java解析XML主要有四種方法。DOM、SAX、JDOM、DOM4J。

第一、DOM解析

    DOM 是用與平臺和語言無關的方式表示 XML 文檔的官方 W3C 標準。DOM 是以層次結構組織的節點或信息片斷的集合。這個層次結構允許開發人員在樹中尋找特定信息。分析該結構通常需要加載整個文檔和構造層次結構,然後才能做任何工作。由於它是基於信息層次的,因而 DOM 被認爲是基於樹或基於對象的。DOM 以及廣義的基於樹的處理具有幾個優點。首先,由於樹在內存中是持久的,因此可以修改它以便應用程序能對數據和結構作出更改。它還可以在任何時候在樹中上下導航,而不是像 SAX 那樣是一次性的處理。DOM 使用起來也要簡單得多。 

  另一方面,對於特別大的文檔,解析和加載整個文檔可能很慢且很耗資源,因此使用其他手段來處理這樣的數據會更好。這些基於事件的模型,比如 SAX。 

  Bean文件: 

[java] view plain copy
  1. package com.test;   
  2.   
  3.   import java.io.*;   
  4.   import java.util.*;   
  5.   import org.w3c.dom.*;   
  6.   import javax.xml.parsers.*;   
  7.   
  8.   public class MyXMLReader{   
  9.   
  10.   public static void main(String arge[]){   
  11.     long lasting =System.currentTimeMillis();   
  12.     try{   
  13.      File f=new File("data_10k.xml");   
  14.      DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();   
  15.      DocumentBuilder builder=factory.newDocumentBuilder();   
  16.      Document doc = builder.parse(f);   
  17.      NodeList nl = doc.getElementsByTagName("VALUE");   
  18.      for (int i=0;i<nl.getLength();i++){   
  19.       System.out.print("車牌號碼:" + doc.getElementsByTagName("NO").item(i).getFirstChild().getNodeValue());   
  20.       System.out.println(" 車主地址:" + doc.getElementsByTagName("ADDR").item(i).getFirstChild().getNodeValue());   
  21.       }   
  22.     }catch(Exception e){   
  23.      e.printStackTrace();   
  24.     }   
  25.     System.out.println("運行時間:"+(System.currentTimeMillis() - lasting)+" 毫秒");   
  26.     }   
  27.   }   


   10k消耗時間:265 203 219 172 
  100k消耗時間:9172 9016 8891 9000 
  1000k消耗時間:691719 675407 708375 739656 

  10000k消耗時間:OutOfMemoryError

DOM:XmlUtils


import java.io.CharArrayReader;
import java.io.File;
import java.io.FileFilter;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;


public class XmlUtils {
public static final String BR = System.getProperty("line.separator");
static final FileFilter xmlFileExtFilter = new FileFilter() {
public boolean accept(File paramFile) {
return paramFile.getName().endsWith(".xml");
}
};


public static Document load(String paramString) throws Exception {
DocumentBuilderFactory localDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
localDocumentBuilderFactory.setIgnoringComments(false);
localDocumentBuilderFactory.setIgnoringElementContentWhitespace(false);
localDocumentBuilderFactory.setValidating(false);
localDocumentBuilderFactory.setCoalescing(true);
DocumentBuilder localDocumentBuilder = localDocumentBuilderFactory.newDocumentBuilder();
return localDocumentBuilder.parse(paramString);
}


public static Document load(File paramFile) throws Exception {
DocumentBuilderFactory localDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
localDocumentBuilderFactory.setIgnoringComments(false);
localDocumentBuilderFactory.setIgnoringElementContentWhitespace(false);
localDocumentBuilderFactory.setValidating(false);
localDocumentBuilderFactory.setCoalescing(true);
DocumentBuilder localDocumentBuilder = localDocumentBuilderFactory.newDocumentBuilder();
return localDocumentBuilder.parse(paramFile);
}


public static String getFileName(String paramString) {
Pattern localPattern = Pattern.compile("[^\\" + File.separator + "]+.xml");
Matcher localMatcher = localPattern.matcher(paramString);
if (localMatcher.find())
return localMatcher.group().substring(0, localMatcher.group().length() - 4);
return "";
}


public static boolean checkValidity(String paramString) {
String[] arrayOfString = paramString.split(".");
return arrayOfString[(arrayOfString.length - 1)].equals("xml");
}


public static boolean isXml(String paramString) {
return paramString.toLowerCase().endsWith("xml");
}


public static Document loadStringWithoutTitle(String paramString) throws Exception {
paramString = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + BR + paramString;
return loadString(paramString);
}


public static Document loadString(String paramString) throws Exception {
DocumentBuilderFactory localDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
localDocumentBuilderFactory.setIgnoringComments(false);
localDocumentBuilderFactory.setIgnoringElementContentWhitespace(false);
localDocumentBuilderFactory.setValidating(false);
localDocumentBuilderFactory.setCoalescing(false);
DocumentBuilder localDocumentBuilder = localDocumentBuilderFactory.newDocumentBuilder();
char[] arrayOfChar = new char[paramString.length()];
paramString.getChars(0, paramString.length(), arrayOfChar, 0);
InputSource localInputSource = new InputSource(new CharArrayReader(arrayOfChar));
return localDocumentBuilder.parse(localInputSource);
}


public static String getTextByFullName(Document paramDocument, String paramString) {
String[] arrayOfString = toStringArray(paramString, ".");
Element localElement = paramDocument.getDocumentElement();
for (int i = 1; i < arrayOfString.length; i++)
localElement = getChildByName(localElement, arrayOfString[i]);
return getText(localElement);
}


public static String getTextByFullName(Element paramElement, String paramString) {
String[] arrayOfString = toStringArray(paramString, ".");
Element localElement = paramElement;
for (int i = 0; i < arrayOfString.length; i++)
localElement = getChildByName(localElement, arrayOfString[i]);
return getText(localElement);
}


public static String getChildText(Element paramElement, String paramString) {
Element localElement = getChildByName(paramElement, paramString);
if (localElement == null)
return "";
return getText(localElement);
}


public static Element[] getChildrenByName(Element paramElement, String paramString) {
NodeList localNodeList = paramElement.getChildNodes();
int i = localNodeList.getLength();
LinkedList localLinkedList = new LinkedList();
for (int j = 0; j < i; j++) {
Node localNode = localNodeList.item(j);
if ((localNode.getNodeType() != 1) || (!localNode.getNodeName().equals(paramString)))
continue;
localLinkedList.add(localNode);
}
return (Element[]) localLinkedList.toArray(new Element[localLinkedList.size()]);
}


public static Element getChildByName(Element paramElement, String paramString) {
Element[] arrayOfElement = getChildrenByName(paramElement, paramString);
if (arrayOfElement.length == 0)
return null;
if (arrayOfElement.length > 1)
throw new IllegalStateException(
"Too many (" + arrayOfElement.length + ") '" + paramString + "' elements found!");
return arrayOfElement[0];
}


public static String getText(Element paramElement) {
NodeList localNodeList = paramElement.getChildNodes();
int i = localNodeList.getLength();
for (int j = 0; j < i; j++) {
Node localNode = localNodeList.item(j);
if (localNode.getNodeType() == 3)
return localNode.getNodeValue();
}
return "";
}


public static String getAttribute(Element paramElement, String paramString) {
return paramElement.getAttribute(paramString);
}


public static int getIntValue(Element paramElement) {
return Integer.valueOf(getText(paramElement)).intValue();
}


public static Long getLongValue(Element paramElement) {
return Long.valueOf(getText(paramElement));
}


public static byte getByteValue(Element paramElement) {
return Byte.valueOf(getText(paramElement)).byteValue();
}


public static Map<String, Object> getProperties(Element paramElement) {
HashMap localHashMap = new HashMap();
Element[] arrayOfElement = getChildrenByName(paramElement, "property");
for (int i = 0; i < arrayOfElement.length; i++) {
String str1 = arrayOfElement[i].getAttribute("name");
String str2 = arrayOfElement[i].getAttribute("type");
String str3 = getText(arrayOfElement[i]);
try {
Class localClass = Class.forName(str2);
Constructor localConstructor = localClass.getConstructor(new Class[] { String.class });
Object localObject = localConstructor.newInstance(new Object[] { str3 });
localHashMap.put(str1, localObject);
} catch (Exception localException) {
System.err.println(
"Unable to parse property '" + str1 + "'='" + str3 + "': " + localException.toString());
}
}
return localHashMap;
}


public static void save(String paramString, Document paramDocument) throws Exception {
DOMSource localDOMSource = new DOMSource(paramDocument);
File localFile1 = new File(paramString);
File localFile2 = localFile1.getParentFile();
localFile2.mkdirs();
StreamResult localStreamResult = new StreamResult(localFile1);
try {
TransformerFactory localTransformerFactory = TransformerFactory.newInstance();
Transformer localTransformer = localTransformerFactory.newTransformer();
Properties localProperties = localTransformer.getOutputProperties();
localProperties.setProperty("encoding", "UTF-8");
localProperties.setProperty("indent", "yes");
localTransformer.setOutputProperties(localProperties);
localTransformer.transform(localDOMSource, localStreamResult);
} catch (TransformerConfigurationException localTransformerConfigurationException) {
localTransformerConfigurationException.printStackTrace();
} catch (TransformerException localTransformerException) {
localTransformerException.printStackTrace();
}
}


public static Document blankDocument(String paramString) throws Exception {
DocumentBuilderFactory localDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
localDocumentBuilderFactory.setIgnoringComments(false);
localDocumentBuilderFactory.setIgnoringElementContentWhitespace(false);
localDocumentBuilderFactory.setValidating(false);
localDocumentBuilderFactory.setCoalescing(false);
DocumentBuilder localDocumentBuilder = localDocumentBuilderFactory.newDocumentBuilder();
Document localDocument = localDocumentBuilder.newDocument();
Element localElement = localDocument.createElement(paramString);
localDocument.appendChild(localElement);
return localDocument;
}


public static Element createChild(Document paramDocument, Element paramElement, String paramString) {
Element localElement = paramDocument.createElement(paramString);
paramElement.appendChild(localElement);
return localElement;
}


public static void createChildText(Document paramDocument, Element paramElement, String paramString1,
String paramString2) {
Element localElement = paramDocument.createElement(paramString1);
localElement.appendChild(paramDocument.createTextNode(paramString2 == null ? "" : paramString2));
paramElement.appendChild(localElement);
}


public static void createChildTextWithComment(Document paramDocument, Element paramElement, String paramString1,
String paramString2, String paramString3) {
Element localElement = paramDocument.createElement(paramString1);
localElement.appendChild(paramDocument.createTextNode(paramString2 == null ? "" : paramString2));
Comment localComment = paramDocument.createComment(paramString3);
paramElement.appendChild(localComment);
paramElement.appendChild(localElement);
}


public static void createComment(Document paramDocument, String paramString) {
Comment localComment = paramDocument.createComment(paramString);
paramDocument.getDocumentElement().appendChild(localComment);
}


public static void createOptionalChildText(Document paramDocument, Element paramElement, String paramString1,
String paramString2) {
if ((paramString2 == null) || (paramString2.length() == 0))
return;
Element localElement = paramDocument.createElement(paramString1);
localElement.appendChild(paramDocument.createTextNode(paramString2));
paramElement.appendChild(localElement);
}


public static String Doc2String(Document paramDocument) {
try {
DOMSource localDOMSource = new DOMSource(paramDocument);
StringWriter localStringWriter = new StringWriter();
StreamResult localStreamResult = new StreamResult(localStringWriter);
TransformerFactory localTransformerFactory = TransformerFactory.newInstance();
Transformer localTransformer = localTransformerFactory.newTransformer();
localTransformer.transform(localDOMSource, localStreamResult);
return localStringWriter.toString();
} catch (Exception localException) {
localException.printStackTrace();
}
return null;
}


public static void applyProperties(Object paramObject, Element paramElement) {
Map<String, Object> localMap = getProperties(paramElement);
Iterator<String> localIterator = localMap.keySet().iterator();
Field[] arrayOfField = paramObject.getClass().getFields();
Method[] arrayOfMethod = paramObject.getClass().getMethods();
while (localIterator.hasNext()) {
String str = (String) localIterator.next();
Object localObject = localMap.get(str);
try {
for (int i = 0; i < arrayOfField.length; i++) {
if ((!arrayOfField[i].getName().equalsIgnoreCase(str))
|| (!isTypeMatch(arrayOfField[i].getType(), localObject.getClass())))
continue;
arrayOfField[i].set(paramObject, localObject);
System.err.println("Set field " + arrayOfField[i].getName() + "=" + localObject);
break;
}
for (int i = 0; i < arrayOfMethod.length; i++) {
if ((!arrayOfMethod[i].getName().equalsIgnoreCase("set" + str))
|| (arrayOfMethod[i].getParameterTypes().length != 1)
|| (!isTypeMatch(arrayOfMethod[i].getParameterTypes()[0], localObject.getClass())))
continue;
arrayOfMethod[i].invoke(paramObject, new Object[] { localObject });
System.err.println("Set method " + arrayOfMethod[i].getName() + "=" + localObject);
break;
}
} catch (Exception localException) {
System.err.println("Unable to apply property '" + str + "': " + localException.toString());
}
}
}


private static boolean isTypeMatch(Class<?> paramClass, Class<? extends Object> paramClass1) {
if (paramClass.equals(paramClass1))
return true;
if (paramClass.isPrimitive()) {
if ((paramClass.getName().equals("int")) && (paramClass1.getName().equals("java.lang.Integer")))
return true;
if ((paramClass.getName().equals("long")) && (paramClass1.getName().equals("java.lang.Long")))
return true;
if ((paramClass.getName().equals("float")) && (paramClass1.getName().equals("java.lang.Float")))
return true;
if ((paramClass.getName().equals("double")) && (paramClass1.getName().equals("java.lang.Double")))
return true;
if ((paramClass.getName().equals("char")) && (paramClass1.getName().equals("java.lang.Character")))
return true;
if ((paramClass.getName().equals("byte")) && (paramClass1.getName().equals("java.lang.Byte")))
return true;
if ((paramClass.getName().equals("short")) && (paramClass1.getName().equals("java.lang.Short")))
return true;
if ((paramClass.getName().equals("boolean")) && (paramClass1.getName().equals("java.lang.Boolean")))
return true;
}
return false;
}


public static final FileFilter getXmlFileExtFilter() {
return xmlFileExtFilter;
}

public static final String[] toStringArray(String paramString1, String paramString2) {
if ((paramString1 == null) || (paramString1.length() == 0))
return new String[0];
StringTokenizer localStringTokenizer = new StringTokenizer(paramString1, paramString2);
String[] arrayOfString = new String[localStringTokenizer.countTokens()];
for (int i = 0; i < arrayOfString.length; i++)
arrayOfString[i] = localStringTokenizer.nextToken();
return arrayOfString;
}
}


第二、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 解析器的時候編碼工作會比較困難,而且很難同時訪問同一個文檔中的多處不同數據。 

  Bean文件: 

[java] view plain copy
  1. <span style="font-family:Microsoft YaHei;">package com.test;   
  2.   import org.xml.sax.*;   
  3.   import org.xml.sax.helpers.*;   
  4.   import javax.xml.parsers.*;   
  5.   
  6.   public class MyXMLReader extends DefaultHandler {   
  7.   
  8.   java.util.Stack tags = new java.util.Stack();   
  9.   
  10.   public MyXMLReader() {   
  11.   super();   
  12.   }   
  13.   
  14.   public static void main(String args[]) {   
  15.   long lasting = System.currentTimeMillis();   
  16.   try {   
  17.    SAXParserFactory sf = SAXParserFactory.newInstance();   
  18.    SAXParser sp = sf.newSAXParser();   
  19.    MyXMLReader reader = new MyXMLReader();   
  20.    sp.parse(new InputSource("data_10k.xml"), reader);   
  21.   } catch (Exception e) {   
  22.    e.printStackTrace();   
  23.   }   
  24.   System.out.println("運行時間:" + (System.currentTimeMillis() - lasting) + " 毫秒");   
  25.   }   
  26.   
  27.   public void characters(char ch[], int start, int length) throws SAXException {   
  28.   String tag = (String) tags.peek();   
  29.   if (tag.equals("NO")) {   
  30.    System.out.print("車牌號碼:" + new String(ch, start, length));   
  31.   }   
  32.   if (tag.equals("ADDR")) {   
  33.   System.out.println(" 地址:" + new String(ch, start, length));   
  34.   }   
  35.   }   
  36.   
  37.   public void startElement(   
  38.   String uri,   
  39.   String localName,   
  40.   String qName,   
  41.   Attributes attrs) {   
  42.   tags.push(qName);   
  43.   }   
  44.   } </span>  
10k消耗時間:110 47 109 78 
  100k消耗時間:344 406 375 422 
  1000k消耗時間:3234 3281 3688 3312 

  10000k消耗時間:32578 34313 31797 31890 30328


第三、JDOM解析

        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 許可證變體下發布的開放源碼。 

  Bean文件:

[java] view plain copy
  1. package com.test;   
  2.   
  3.   import java.io.*;   
  4.   import java.util.*;   
  5.   import org.jdom.*;   
  6.   import org.jdom.input.*;   
  7.   
  8.   public class MyXMLReader {   
  9.   
  10.   public static void main(String arge[]) {   
  11.   long lasting = System.currentTimeMillis();   
  12.   try {   
  13.    SAXBuilder builder = new SAXBuilder();   
  14.    Document doc = builder.build(new File("data_10k.xml"));   
  15.    Element foo = doc.getRootElement();   
  16.    List allChildren = foo.getChildren();   
  17.    for(int i=0;i<allChildren.size();i++) {   
  18.     System.out.print("車牌號碼:" + ((Element)allChildren.get(i)).getChild("NO").getText());   
  19.     System.out.println(" 車主地址:" + ((Element)allChildren.get(i)).getChild("ADDR").getText());   
  20.    }   
  21.   } catch (Exception e) {   
  22.    e.printStackTrace();   
  23.   }   
  24.   System.out.println("運行時間:" + (System.currentTimeMillis() - lasting) + " 毫秒");   
  25.   }   
  26.   }   
10k消耗時間:125 62 187 94 
  100k消耗時間:704 625 640 766 
  1000k消耗時間:27984 30750 27859 30656 
  10000k消耗時間:OutOfMemoryError

 dom4j是一個Java的XML API,類似於jdom,用來讀寫XML文件的。dom4j是一個非常非常優秀的Java XML API,具有性能優異、功能強大和極端易用使用的特點,同時它也是一個開放源代碼的軟件,可以在SourceForge上找到它.


第 四、DOM4J解析

雖然 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。 

  Bean文件: 

[java] view plain copy
  1. package com.test;   
  2.   
  3.   import java.io.*;   
  4.   import java.util.*;   
  5.   import org.dom4j.*;   
  6.   import org.dom4j.io.*;   
  7.   
  8.   public class MyXMLReader {   
  9.   
  10.   public static void main(String arge[]) {   
  11.   long lasting = System.currentTimeMillis();   
  12.   try {   
  13.    File f = new File("data_10k.xml");   
  14.    SAXReader reader = new SAXReader();   
  15.    Document doc = reader.read(f);   
  16.    Element root = doc.getRootElement();   
  17.    Element foo;   
  18.    for (Iterator i = root.elementIterator("VALUE"); i.hasNext();) {   
  19.     foo = (Element) i.next();   
  20.     System.out.print("車牌號碼:" + foo.elementText("NO"));   
  21.     System.out.println(" 車主地址:" + foo.elementText("ADDR"));   
  22.    }   
  23.   } catch (Exception e) {   
  24.    e.printStackTrace();   
  25.   }   
  26.   System.out.println("運行時間:" + (System.currentTimeMillis() - lasting) + " 毫秒");   
  27.   }   
  28.   }   
10k消耗時間:109 78 109 31 
  100k消耗時間:297 359 172 312 
  1000k消耗時間:2281 2359 2344 2469 
  10000k消耗時間:20938 19922 20031 21078

       對主流的Java XML API進行的性能、功能和易用性的評測,dom4j無論在那個方面都是非常出色的。如今你可以看到越來越多的Java軟件都在使用dom4j來讀寫XML,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。

       使用Dom4j開發,需下載dom4j相應的jar文件

        1.官網下載: http://www.dom4j.org/dom4j-1.6.1/

         2.dom4j是sourceforge.net上的一個開源項目,因此可以到http://sourceforge.net/projects/dom4j下載其最新版.

         對於下載的zip文件進行解壓後的效果如下:

        

 打開dom4j-1.6.1的解壓文件


在這裏可以看到有docs幫助的文件夾,也有需要使用dom4j解析xml文件的dom4j-1.6.1.jar文件.我們只需要把dom4j-1.6.1.jar文件構建到我們開發的項目中就可以使用dom4j開發了.

下面我以Myeclipse創建Java項目的構建方法爲例說明.

首先創建一個demo項目,在demo項目中創建一個lib文件,把dom4j-1.6.1.jar文件拷貝到lib中,然後右鍵dom4j-1.6.1jar文件

   

點擊Add to Build Path即可構建到項目中去了.

備註:如果進行的是web項目開發,我們只需要把它拷貝到web-inf/lib中去即可,會自動構建到web項目中.


在項目開發的過程中可以參考docs文件夾的(幫助文檔),找到index.html打開,點擊Quick start可以通過幫助文檔進行學習 dom4j進行xml的解析.


    下面我對我認爲api中重要的方法進行翻譯說明如下:

一、DOM4j中,獲得Document對象的方式有三種:

[java] view plain copy
  1. 1.讀取XML文件,獲得document對象              
  2.                   SAXReader reader = new SAXReader();                
  3.        Document   document = reader.read(new File("csdn.xml"));  
  4. 2.解析XML形式的文本,得到document對象.  
  5.                   String text = "<csdn></csdn>";              
  6.                   Document document = DocumentHelper.parseText(text);  
  7. 3.主動創建document對象.  
  8.                  Document document = DocumentHelper.createDocument();             //創建根節點  
  9.                  Element root = document.addElement("csdn");  

二、節點對象操作的方法

[java] view plain copy
  1. 1.獲取文檔的根節點.  
  2.       Element root = document.getRootElement();  
  3.     2.取得某個節點的子節點.  
  4.       Element element=node.element(“四大名著");  
  5.     3.取得節點的文字  
  6.         String text=node.getText();  
  7.     4.取得某節點下所有名爲“csdn”的子節點,並進行遍歷.  
  8.        List nodes = rootElm.elements("csdn");   
  9.          for (Iterator it = nodes.iterator(); it.hasNext();) {     
  10.       Element elm = (Element) it.next();    
  11.     // do something  
  12.  }  
  13.      5.對某節點下的所有子節點進行遍歷.      
  14.       for(Iterator it=root.elementIterator();it.hasNext();){        
  15.         Element element = (Element) it.next();        
  16.        // do something   
  17.  }  
  18.     6.在某節點下添加子節點  
  19.       Element elm = newElm.addElement("朝代");  
  20.     7.設置節點文字.  elm.setText("明朝");  
  21.     8.刪除某節點.//childElement是待刪除的節點,parentElement是其父節點  parentElement.remove(childElment);  
  22.     9.添加一個CDATA節點.Element contentElm = infoElm.addElement("content");contentElm.addCDATA(“cdata區域”);  

三、節點對象的屬性方法操作

[java] view plain copy
  1. 1.取得某節點下的某屬性    Element root=document.getRootElement();        //屬性名name  
  2.          Attribute attribute=root.attribute("id");  
  3.     2.取得屬性的文字  
  4.     String text=attribute.getText();  
  5.     3.刪除某屬性 Attribute attribute=root.attribute("size"); root.remove(attribute);  
  6.     4.遍歷某節點的所有屬性     
  7.       Element root=document.getRootElement();        
  8.        for(Iterator it=root.attributeIterator();it.hasNext();){          
  9.            Attribute attribute = (Attribute) it.next();           
  10.            String text=attribute.getText();          
  11.            System.out.println(text);    
  12.   }  
  13.     5.設置某節點的屬性和文字.   newMemberElm.addAttribute("name""sitinspring");  
  14.     6.設置屬性的文字   Attribute attribute=root.attribute("name");   attribute.setText("csdn");  

四、將文檔寫入XML文件

[java] view plain copy
  1. 1.文檔中全爲英文,不設置編碼,直接寫入的形式.    
  2.        XMLWriter writer = new XMLWriter(new  FileWriter("ot.xml"));   
  3.        writer.write(document);    
  4.        writer.close();  
  5.     2.文檔中含有中文,設置編碼格式寫入的形式.  
  6.        OutputFormat format = OutputFormat.createPrettyPrint();// 創建文件輸出的時候,自動縮進的格式                    
  7.        format.setEncoding("UTF-8");//設置編碼  
  8.        XMLWriter writer = new XMLWriter(newFileWriter("output.xml"),format);  
  9.        writer.write(document);  
  10.        writer.close();  

五、字符串與XML的轉換

[java] view plain copy
  1. 1.將字符串轉化爲XML  
  2.       String text = "<csdn> <java>Java班</java></csdn>";  
  3.       Document document = DocumentHelper.parseText(text);  
  4.     2.將文檔或節點的XML轉化爲字符串.  
  5.        SAXReader reader = new SAXReader();  
  6.        Document   document = reader.read(new File("csdn.xml"));              
  7.        Element root=document.getRootElement();      
  8.        String docXmlText=document.asXML();  
  9.        String rootXmlText=root.asXML();  
  10.        Element memberElm=root.element("csdn");  
  11.        String memberXmlText=memberElm.asXML();  
六、案例(解析sida.xml文件並對其進行curd的操作)

1.sida.xml描述四大名著的操作,文件內容如下

[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <四大名著>  
  3.     <西遊記 id="x001">  
  4.         <作者>吳承恩1</作者>  
  5.         <作者>吳承恩2</作者>  
  6.         <朝代>明朝</朝代>  
  7.     </西遊記>  
  8.     <紅樓夢 id="x002">  
  9.         <作者>曹雪芹</作者>  
  10.     </紅樓夢>  
  11. </四大名著>  
2.解析類測試操作

[java] view plain copy
  1. package dom4j;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileOutputStream;  
  5. import java.io.FileWriter;  
  6. import java.io.OutputStreamWriter;  
  7. import java.nio.charset.Charset;  
  8. import java.nio.charset.CharsetEncoder;  
  9. import java.util.Iterator;  
  10. import java.util.List;  
  11.   
  12. import org.dom4j.Attribute;  
  13. import org.dom4j.Document;  
  14. import org.dom4j.Element;  
  15. import org.dom4j.io.OutputFormat;  
  16. import org.dom4j.io.SAXReader;  
  17. import org.dom4j.io.XMLWriter;  
  18. import org.junit.Test;  
  19.   
  20. public class Demo01 {  
  21.   
  22.     @Test  
  23.     public void test() throws Exception {  
  24.   
  25.         // 創建saxReader對象  
  26.         SAXReader reader = new SAXReader();  
  27.         // 通過read方法讀取一個文件 轉換成Document對象  
  28.         Document document = reader.read(new File("src/dom4j/sida.xml"));  
  29.         //獲取根節點元素對象  
  30.         Element node = document.getRootElement();  
  31.         //遍歷所有的元素節點  
  32.         listNodes(node);  
  33.   
  34.         // 獲取四大名著元素節點中,子節點名稱爲紅樓夢元素節點。  
  35.         Element element = node.element("紅樓夢");  
  36.         //獲取element的id屬性節點對象  
  37.         Attribute attr = element.attribute("id");  
  38.         //刪除屬性  
  39.         element.remove(attr);  
  40.         //添加新的屬性  
  41.         element.addAttribute("name""作者");  
  42.         // 在紅樓夢元素節點中添加朝代元素的節點  
  43.         Element newElement = element.addElement("朝代");  
  44.         newElement.setText("清朝");  
  45.         //獲取element中的作者元素節點對象  
  46.         Element author = element.element("作者");  
  47.         //刪除元素節點  
  48.         boolean flag = element.remove(author);  
  49.         //返回true代碼刪除成功,否則失敗  
  50.         System.out.println(flag);  
  51.         //添加CDATA區域  
  52.         element.addCDATA("紅樓夢,是一部愛情小說.");  
  53.         // 寫入到一個新的文件中  
  54.         writer(document);  
  55.   
  56.     }  
  57.   
  58.     /** 
  59.      * 把document對象寫入新的文件 
  60.      *  
  61.      * @param document 
  62.      * @throws Exception 
  63.      */  
  64.     public void writer(Document document) throws Exception {  
  65.         // 緊湊的格式  
  66.         // OutputFormat format = OutputFormat.createCompactFormat();  
  67.         // 排版縮進的格式  
  68.         OutputFormat format = OutputFormat.createPrettyPrint();  
  69.         // 設置編碼  
  70.         format.setEncoding("UTF-8");  
  71.         // 創建XMLWriter對象,指定了寫出文件及編碼格式  
  72.         // XMLWriter writer = new XMLWriter(new FileWriter(new  
  73.         // File("src//a.xml")),format);  
  74.         XMLWriter writer = new XMLWriter(new OutputStreamWriter(  
  75.                 new FileOutputStream(new File("src//a.xml")), "UTF-8"), format);  
  76.         // 寫入  
  77.         writer.write(document);  
  78.         // 立即寫入  
  79.         writer.flush();  
  80.         // 關閉操作  
  81.         writer.close();  
  82.     }  
  83.   
  84.     /** 
  85.      * 遍歷當前節點元素下面的所有(元素的)子節點 
  86.      *  
  87.      * @param node 
  88.      */  
  89.     public void listNodes(Element node) {  
  90.         System.out.println("當前節點的名稱::" + node.getName());  
  91.         // 獲取當前節點的所有屬性節點  
  92.         List<Attribute> list = node.attributes();  
  93.         // 遍歷屬性節點  
  94.         for (Attribute attr : list) {  
  95.             System.out.println(attr.getText() + "-----" + attr.getName()  
  96.                     + "---" + attr.getValue());  
  97.         }  
  98.   
  99.         if (!(node.getTextTrim().equals(""))) {  
  100.             System.out.println("文本內容::::" + node.getText());  
  101.         }  
  102.   
  103.         // 當前節點下面子節點迭代器  
  104.         Iterator<Element> it = node.elementIterator();  
  105.         // 遍歷  
  106.         while (it.hasNext()) {  
  107.             // 獲取某個子節點對象  
  108.             Element e = it.next();  
  109.             // 對子節點進行遍歷  
  110.             listNodes(e);  
  111.         }  
  112.     }  
  113.   
  114.     /** 
  115.      * 介紹Element中的element方法和elements方法的使用 
  116.      *  
  117.      * @param node 
  118.      */  
  119.     public void elementMethod(Element node) {  
  120.         // 獲取node節點中,子節點的元素名稱爲西遊記的元素節點。  
  121.         Element e = node.element("西遊記");  
  122.         // 獲取西遊記元素節點中,子節點爲作者的元素節點(可以看到只能獲取第一個作者元素節點)  
  123.         Element author = e.element("作者");  
  124.   
  125.         System.out.println(e.getName() + "----" + author.getText());  
  126.   
  127.         // 獲取西遊記這個元素節點 中,所有子節點名稱爲作者元素的節點 。  
  128.   
  129.         List<Element> authors = e.elements("作者");  
  130.         for (Element aut : authors) {  
  131.             System.out.println(aut.getText());  
  132.         }  
  133.   
  134.         // 獲取西遊記這個元素節點 所有元素的子節點。  
  135.         List<Element> elements = e.elements();  
  136.   
  137.         for (Element el : elements) {  
  138.             System.out.println(el.getText());  
  139.         }  
  140.   
  141.     }  
  142.   
  143. }  
自己適當註釋部分代碼觀察運行效果,反覆練習,希望你對dom4j有進一步的瞭解.


七、字符串與XML互轉換案例

[java] view plain copy
  1. package dom4j;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileOutputStream;  
  5. import java.io.OutputStreamWriter;  
  6.   
  7. import org.dom4j.Document;  
  8. import org.dom4j.DocumentHelper;  
  9. import org.dom4j.Element;  
  10. import org.dom4j.io.OutputFormat;  
  11. import org.dom4j.io.SAXReader;  
  12. import org.dom4j.io.XMLWriter;  
  13. import org.junit.Test;  
  14.   
  15. public class Demo02 {  
  16.   
  17.     @Test  
  18.     public void test() throws Exception {  
  19.   
  20.         // 創建saxreader對象  
  21.         SAXReader reader = new SAXReader();  
  22.         // 讀取一個文件,把這個文件轉換成Document對象  
  23.         Document document = reader.read(new File("src//c.xml"));  
  24.         // 獲取根元素  
  25.         Element root = document.getRootElement();  
  26.         // 把文檔轉換字符串  
  27.         String docXmlText = document.asXML();  
  28.         System.out.println(docXmlText);  
  29.         System.out.println("---------------------------");  
  30.         // csdn元素標籤根轉換的內容  
  31.         String rootXmlText = root.asXML();  
  32.         System.out.println(rootXmlText);  
  33.         System.out.println("---------------------------");  
  34.         // 獲取java元素標籤 內的內容  
  35.         Element e = root.element("java");  
  36.         System.out.println(e.asXML());  
  37.   
  38.     }  
  39.   
  40.     /** 
  41.      * 創建一個document對象 往document對象中添加節點元素 轉存爲xml文件 
  42.      *  
  43.      * @throws Exception 
  44.      */  
  45.     public void test2() throws Exception {  
  46.   
  47.         Document document = DocumentHelper.createDocument();// 創建根節點  
  48.         Element root = document.addElement("csdn");  
  49.         Element java = root.addElement("java");  
  50.         java.setText("java班");  
  51.         Element ios = root.addElement("ios");  
  52.         ios.setText("ios班");  
  53.   
  54.         writer(document);  
  55.     }  
  56.   
  57.     /** 
  58.      * 把一個文本字符串轉換Document對象 
  59.      *  
  60.      * @throws Exception 
  61.      */  
  62.     public void test1() throws Exception {  
  63.         String text = "<csdn><java>Java班</java><net>Net班</net></csdn>";  
  64.         Document document = DocumentHelper.parseText(text);  
  65.         Element e = document.getRootElement();  
  66.         System.out.println(e.getName());  
  67.         writer(document);  
  68.     }  
  69.   
  70.     /** 
  71.      * 把document對象寫入新的文件 
  72.      *  
  73.      * @param document 
  74.      * @throws Exception 
  75.      */  
  76.     public void writer(Document document) throws Exception {  
  77.         // 緊湊的格式  
  78.         // OutputFormat format = OutputFormat.createCompactFormat();  
  79.         // 排版縮進的格式  
  80.         OutputFormat format = OutputFormat.createPrettyPrint();  
  81.         // 設置編碼  
  82.         format.setEncoding("UTF-8");  
  83.         // 創建XMLWriter對象,指定了寫出文件及編碼格式  
  84.         // XMLWriter writer = new XMLWriter(new FileWriter(new  
  85.         // File("src//a.xml")),format);  
  86.         XMLWriter writer = new XMLWriter(new OutputStreamWriter(  
  87.                 new FileOutputStream(new File("src//c.xml")), "UTF-8"), format);  
  88.         // 寫入  
  89.         writer.write(document);  
  90.         // 立即寫入  
  91.         writer.flush();  
  92.         // 關閉操作  
  93.         writer.close();  
  94.     }  
  95. }  


XML解析總結:

1、【DOM】
DOM是基於樹的結構,通常需要加載整文檔和構造DOM樹,然後才能開始工作。
優點:
    a、由於整棵樹在內存中,因此可以對xml文檔隨機訪問
    b、可以對xml文檔進行修改操作
    c、較sax,dom使用也更簡單。
缺點:
    a、整個文檔必須一次性解析完
    a、由於整個文檔都需要載入內存,對於大文檔成本高
2、【SAX】
SAX類似流媒體,它基於事件驅動的,因此無需將整個文檔載入內存,使用者只需要監聽自己感興趣的事件即可。
優點:
    a、無需將整個xml文檔載入內存,因此消耗內存少
    b、可以註冊多個ContentHandler
缺點:
    a、不能隨機的訪問xml中的節點
    b、不能修改文檔
3、【JDOM】
JDOM是純Java的處理XML的API,其API中大量使用Collections類,
優點:
    a、DOM方式的優點
    b、具有SAX的Java規則
缺點
    a、DOM方式的缺點
4、【DOM4J】
    這4中xml解析方式中,最優秀的一個,集易用和性能於一身。

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

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

  無疑,DOM4J是這場測試的獲勝者,目前許多開源項目中大量採用 DOM4J,例如大名鼎鼎的 Hibernate 也用 DOM4J 來讀取 XML 配置文件。如果不考慮可移植性,那就採用DOM4J吧!




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章