1. 程式人生 > >xml檔案四中解析方式

xml檔案四中解析方式

       XML現在已經成為一種通用的資料交換格式,平臺的無關性使得很多場合都需要用到XML。小編將將簡單介紹一下Java解析XML的四中方法。

     基本的解析方式有兩種,一種叫DOM,另一種叫SAXSAX是基於事件流的解析,DOM是基於XML文件樹結構的解析。假設我們XML的內容和結構如下

<?xml version="1.0" encoding="UTF-8"?>
<config>

	<db-info>

		<driver-name>com.mysql.jdbc.Driver</driver-name>
		<url>jdbc:mysql://localhost:3306/drp</url>
		<user-name>root</user-name>
		<password>123</password>

	</db-info>

</config>
【DOM解析】

     DOM解析是把整個XML文件當做一個物件來處理,首先把整個文件讀入到記憶體中,然後構建一個駐留記憶體的樹結構,然後程式碼就可以使用 DOM 介面來操作這個樹結構。雖然整個文件都在記憶體中,易操作,可隨機訪問,但是浪費時間和空間,需要硬體資源充足。

DomReader類程式碼:

package com.bjpowernode.drp.util;

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.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class DomReader {

	public void readXML(File file) {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder builder = factory.newDocumentBuilder();
			// 獲得文件物件--
			Document doc = builder.parse(file);
			// 獲得根元素
			Element element = doc.getDocumentElement();
			// 用方法遍歷遞迴列印根元素下面所有的ElementNode(包括屬性,TextNode非空的值),用空格分層次顯示.
			listAllChildNodes(element, 0);// 引數0表示設定根節點層次為0
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/*
	 * 遞迴遍歷並列印所有的ElementNode(包括節點的屬性和文字節點的有效內容),按一般的xml樣式展示出來(空格來表示層次)
	 */
	public void listAllChildNodes(Node node, int level) {
		if (node.getNodeType() == Node.ELEMENT_NODE) {
			boolean hasTextChild = false;

			String levelSpace = "";
			for (int i = 0; i < level; i++) {
				levelSpace += "    ";
			}
			// 先列印ElementNode的開始標籤
			System.out.print(levelSpace + "<" + node.getNodeName()
					+ (node.hasAttributes() ? " " : ">"));
			// 遍歷列印節點的所有屬性
			if (node.hasAttributes()) {
				NamedNodeMap nnmap = node.getAttributes();
				for (int i = 0; i < nnmap.getLength(); i++) {
					System.out.print(nnmap.item(i).getNodeName() + "=\""
							+ nnmap.item(i).getNodeValue() + "\""
							+ (i == (nnmap.getLength() - 1) ? "" : " "));
				}
				System.out.print(">");
			}
			// 該ElementNode包含子節點de時候
			if (node.hasChildNodes()) {
				level++;
				// 獲得所有的子節點列表
				NodeList nodelist = node.getChildNodes();
				// 迴圈遍歷取到所有的子節點
				for (int i = 0; i < nodelist.getLength(); i++) {
					if (nodelist.item(i).getNodeType() == Node.TEXT_NODE
							&& (!nodelist.item(i).getTextContent()
									.matches("\\s+"))) {
						hasTextChild = true;
						System.out.print(nodelist.item(i).getTextContent());
					} else if (nodelist.item(i).getNodeType() == Node.ELEMENT_NODE) {
						System.out.println();

						listAllChildNodes(nodelist.item(i), level);
					}
				}
				level--;

			}

			System.out.print(((hasTextChild) ? "" : "\n" + levelSpace) + "</"
					+ node.getNodeName() + ">");
		}
	}

}
測試類程式碼:

package com.bjpowernode.drp.util;

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

/**
 * 解析sys-config.xml檔案
 * 
 * @author happy
 * 
 */
public class XmlConfigReader {

	public static void main(String[] args) throws ParserConfigurationException,
			SAXException, IOException {

		// 獲取需要解析的文件
		File file = new File("src/sys-config.xml");
		(new DomReader()).readXML(file);
	}
}
解析效果圖如下:



【SAX解析】

    為解決DOM的問題,出現了SAXSAX,事件驅動。SAX主要是有四個方法,startDocument(),startElement(),endDocument(),endElement(),SAX是按照xml檔案的順序依次解析的,即當xml檔案開始的時候,呼叫startDocument(),當讀到一個節點時,呼叫startElement(),當結束節點時,呼叫endElement(),結束xml檔案時,呼叫endDocument()

SaxHandler類程式碼:

package com.bjpowernode.drp.util;

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

public class SaxHandler extends DefaultHandler {
	@Override
	public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
		System.out.print(new String(arg0, arg1, arg2));
		super.characters(arg0, arg1, arg2);
	}

	@Override
	public void startDocument() throws SAXException {
		System.out.println("開始解析");
		String s = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
		System.out.println(s);
		super.startDocument();
	}

	@Override
	public void startElement(String arg0, String arg1, String arg2,
			Attributes arg3) throws SAXException {

		System.out.print("<");
		System.out.print(arg2);

		if (arg3 != null) {
			for (int i = 0; i < arg3.getLength(); i++) {
				System.out.print(" " + arg3.getQName(i) + "=\""
						+ arg3.getValue(i) + "\"");
			}
		}
		System.out.print(">");
		super.startElement(arg0, arg1, arg2, arg3);
	}

	@Override
	public void endElement(String arg0, String arg1, String arg2)
			throws SAXException {
		System.out.print("</");
		System.out.print(arg2);
		System.out.print(">");
		super.endElement(arg0, arg1, arg2);
	}

	@Override
	public void endDocument() throws SAXException {
		System.out.println("\n結束解析");
		super.endDocument();
	}
}
測試類程式碼:

package com.bjpowernode.drp.util;

import java.io.IOException;
import java.io.InputStream;

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

import org.xml.sax.SAXException;

/**
 * 解析sys-config.xml檔案
 * 
 * @author happy
 * 
 */
public class XmlConfigReader {

	public static void main(String[] args) throws ParserConfigurationException,
			SAXException, IOException {
		// 1.例項化SAXParserFactory物件
		SAXParserFactory factory = SAXParserFactory.newInstance();
		// 2.建立解析器
		SAXParser parser = factory.newSAXParser();
		// 3.獲取需要解析的文件,生成解析器,最後解析文件
		InputStream is = Thread.currentThread().getContextClassLoader()
				.getResourceAsStream("sys-config.xml");

		SaxHandler dh = new SaxHandler();
		parser.parse(is, dh);
	}
}
執行效果圖如下:



【JDOM解析】

    為減少DOM、SAX的編碼量,出現了JDOM。JDOM文件宣告其目的是“使用20%(或更少)的精力解決80%(或更多)Java/XML問題”(根據學習曲線假定為20%)。JDOM對於大多數Java/XML應用程式來說當然是有用的,並且大多數開發者發現API比DOM容易理解得多。

package com.bjpowernode.drp.util;

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

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

public class JDOMReader {
	// 讀取xml檔案
	@SuppressWarnings("unchecked")
	public void ReadXml(Document document) throws JDOMException, IOException {

		Element root = document.getRootElement();// 獲得根節點<bookstore>
		List<Element> list = root.getChildren();// 獲得根節點的子節點
		for (Element e : list) {
			System.out.println("驅動名稱:" + e.getChildText("driver-name"));
			System.out.println("url:" + e.getChildText("url"));
			System.out.println("使用者名稱:" + e.getChildText("user-name"));
			System.out.println("密碼:" + e.getChildText("password"));
			System.out.println("==========================================");
		}
	}
}
測試類程式碼:

package com.bjpowernode.drp.util;

import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;

import org.jdom2.Document;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.xml.sax.SAXException;

/**
 * 解析sys-config.xml檔案
 * 
 * @author happy
 * 
 */
public class XmlConfigReader {

	public static void main(String[] args) throws ParserConfigurationException,
			SAXException, IOException {
		SAXBuilder builder = new SAXBuilder();// 例項JDOM解析器

		try {
			// 讀取xml檔案
			Document document = builder.build("src/sys-config.xml");
			(new JDOMReader()).ReadXml(document);
		} catch (JDOMException e) {
			e.printStackTrace();
		}

	}
}
執行效果圖:



【DOM4J解析】

        DOM4J是一個非常非常優秀的Java XML API,具有效能優異、功能強大和極端易用使用的特點,同時它也是一個開放原始碼的軟體雖然它代表了完全獨立的開發結果,但是最初,它是JDOM的一種智慧分支,它合併了許多超出基本XML文件表示的功能,包括整合的XPath支援、XMLSchema支援以及用於大文件或流化文件的基於事件的處理。它還提供了構建文件表示的選項,它通過DOM4J API和標準DOM介面具有並行訪問功能。

package com.bjpowernode.drp.util;

import java.io.InputStream;

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

/**
 * 解析sys-config.xml檔案
 * 
 * @author happy
 * 
 */
public class XmlConfigReader {

	public static void main(String[] args) {
		SAXReader reader = new SAXReader();
		InputStream in = Thread.currentThread().getContextClassLoader()
				.getResourceAsStream("sys-config.xml");
		try {
			Document doc = reader.read(in);
			Element driverNameElt = (Element) doc
					.selectObject("/config/db-info/driver-name");
			Element urlElt = (Element) doc.selectObject("/config/db-info/url");
			Element userNameElt = (Element) doc
					.selectObject("/config/db-info/user-name");
			Element passwordElt = (Element) doc
					.selectObject("/config/db-info/password");

			String driverName = driverNameElt.getStringValue();
			String url = urlElt.getStringValue();
			String userName = userNameElt.getStringValue();
			String password = passwordElt.getStringValue();

			System.out.println(driverName);
			System.out.println(url);
			System.out.println(userName);
			System.out.println(password);

		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}
}

執行效果圖如下:



【比較】

①SAX表現較好,這要依賴於它特定的解析方式-事件驅動。一個SAX檢測即將到來的XML流,但並沒有載入到記憶體。

②JDOM和DOM在效能測試時表現不佳,在測試10M文件時記憶體溢位。在小文件情況下還值得考慮使用DOM和JDOM。

③DOM實現廣泛應用於多種程式語言。它還是許多其它與XML相關的標準的基礎,因為它正式獲得W3C推薦,所以在某些型別的專案中可能也需要它(如在JavaScript中使用DOM)。

④DOM4J效能最好,Sun的JAXM也在用DOM4J。目前許多開源專案中大量採用DOM4J,例如大名鼎鼎的Hibernate也用DOM4J來讀取XML配置檔案。如果不考慮可移植性,那就採用DOM4J。