XML基礎+Java解析XML
一:XML基礎
XML是什么:
可擴展的標記語言
XML能干什么:
描述數據、存儲數據、傳輸(交換)數據。
XML與HTML區別:
目的不一樣
XML 被設計用來描述數據,其焦點是數據的內容。
HTML 被設計用來展示數據,其焦點是數據的外觀。
HTML可以不關閉標簽(即標簽可以不成對出現),但XML必須關閉標簽(即標簽必須成對出現)。
HTML中的標簽標識文本如何展示,而XML中的標簽標識文本是什么含義(什么類型的文本)。
XML文檔節點類型
u 文檔(document)
u 元素(element)
u 屬性(attribute)
u 文本(PCDATA--parsed character data)
u 注釋(comment)
u DOCTYPE :主要驗證文檔內容的正確性
u 實體(ENTITIES)
u CDATA(character data)
XML語法
1、聲明:<?xmlversion="1.0" encoding="UTF-8"?>
2、根節點:必須有一個根節點
3、標簽:標簽必須有結束且區分大小寫,標簽必須順序嵌套
4、屬性:必須引號引起值
5、空格會被保留,HTML空格最多保留一個
6、命名規則:命名必須見名知意
a)名字可包含字母、數字以及其他的字符
b)名字不能以數字或者標點符號開始
c)名字不能以字符“xml”(或者XML、Xml)開始
7、名字不能包含空格
8、 不應在 XML 元素名稱中使用 ":" ,這是由於它用於命名空間(namespaces)的保留字。
9、標簽優先於屬性。
10、XML 命名空間可提供避免元素命名沖突的方法。
11、CDATA:字符數據,<![CDATA[字符數據]]> ,字符數據不進行轉義
12、實體:&實體;
Xml約束
XML DTD 約束
DTD(DocType Definition 文檔類型定義)的作用是定義 XML 文檔的合法構建模塊。
它使用一系列的合法元素來定義文檔結構。用於約定XML格式。
1、DTD引用方式
1、內部 <!DOCTYPE 根元素 [元素聲明]>
例如:
<?xml version="1.0"encoding="UTF-8" standalone="yes"?>
<!DOCTYPE 書架 [
<!ELEMENT 書架 (書+)>
<!ELEMENT 書 (書名,作者,售價)>
<!ELEMENT 書名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售價 (#PCDATA)>
]>
<書架>
<書>
<書名>Java就業培訓教程</書名>
<作者>張孝祥</作者>
<售價>39.00元</售價>
</書>
...
</書架>
2、外部私有的 SYSTEM 一般是我們自己定義的,可能只是一個公司內部使用
<!DOCTYPE 根元素 SYSTEM "dtd文件位置">
例如:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE 書架 SYSTEM "book.dtd">
<書架>
<書>
<書名>java編程思想</書名>
<作者>Brnee</作者>
<售價>80</售價>
</書>
</書架>
3、外部公有的 PUBLIC 一般是一些標准,可能非常多的人用
<!DOCTYPE 根元素 PUBLIC "命名空間""dtd文件位置">
首先根據“命名空間”去問環境要相應的dtd文件,如果有,直接提供,如果沒有再根據dtd文件位置找。
例如:<!DOCTYPE web-app PUBLIC
"-//SunMicrosystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
2、例子:
<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend</body>
</note>
3、參考文檔:
點擊打開鏈接
XML Schema 約束
XML Schema 是基於 XML 的 DTD 替代者。XML Schema 描述 XML 文檔的結構。XML Schema 語言也稱作 XML Schema 定義(XML Schema Definition,XSD)。
DTD不是通過XML語法定義文檔結構, 不能定義數據類型和限制Schema通過XML語法定義文檔結構,可以定義數據類型和限制
約定XML格式
- 定義可出現在文檔中的元素
- 定義可出現在文檔中的屬性
- 定義哪個元素是子元素
- 定義子元素的次序
- 定義子元素的數目
- 定義元素是否為空,或者是否可包含文本
- 定義元素和屬性的數據類型
- 定義元素和屬性的默認值以及固定值
1、為何使用Schema
XML Schema 是 DTD 的繼任者
- XML Schema 可針對未來的需求進行擴展
- XML Schema 更完善,功能更強大
- XML Schema 基於 XML 編寫
- XML Schema 支持數據類型和限制
- XML Schema 支持命名空間
2、Schema引用方式
<users xmlns="命名空間"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="命名空間 Schema位置">
如何找Schema,和DTD一樣,首先根據命名空間問環境要,找不到再根據Schema位置找。
3、例子:
- <?xml version="1.0" encoding="UTF-8"?>
- <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
- <!--xs="http://www.w3.org/2001/XMLSchema" 聲名了w3c的名稱空間,方便下面調用 -->
- targetNamespace="http://www.zhong.cn"
- elementFormDefault="qualified">
- <!--
- schema 是根元素
- xmlns:xs="http://www.w3.org/2001/XMLSchema"
- 指明了在schema中使用的元素和數據種類來自http://www.w3.org/2001/XMLSchema名稱空間(namespace)。
- 它也指定了來自"http://www.w3.org/2001/XMLSchema"名稱空間(namespace)的元素和數據種類必須帶前綴“xs:”
- targetNamespace="http://www.zhong.cn"(將全部元素綁定給這個名稱空間)
- 暗示了由這份schema(shiporder, orderperson, shipto, ....)定義的元素來自"http://www.zhong.com"名稱空間
- xmlns="http://www.w3schools.com"
- 指明了默認名稱空間(namespace)是http://www.w3schools.com.
- elementFormDefault="qualified" (“unqualified”)將根節點綁定到名稱空間
- 將所有元素綁定到名稱空間
- -->
- <!--xs:element 指的是element這個元素來自於xs名稱空間 -->
- <xs:element name="shiporder"> <!-- 定義一個元素 shiporder -->
- <xs:complexType> <!-- 類型是:復合類型(里面包含元素或者屬性) -->
- <xs:sequence> <!-- 元素要有順序 -->
- <xs:element name="orderperson" type="xs:string"/> <!-- 定義一個元素 orderperson 類型為:字符串 -->
- <xs:element name="shipto" minOccurs="1" maxOccurs="1"> <!-- 定義一個元素 shipto 最少出現1次,最多出現1次 -->
- <xs:complexType> <!-- shipto元素也是復合類型 -->
- <xs:sequence> <!-- 元素要有順序 -->
- <xs:element name="name" type="xs:string"/> <!-- 在shipto元素中定義一個元素 name 類型為:字符串 -->
- <xs:element name="address" type="xs:string"/>
- <xs:element name="city" type="xs:string"/>
- <xs:element name="country" type="xs:string"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="item" maxOccurs="unbounded"> <!-- 在shiporder元素中定義一個元素 item 出現次數可以無限次 -->
- <xs:complexType>
- <xs:sequence>
- <xs:element name="title" type="xs:string"/>
- <xs:element name="note" type="xs:string" minOccurs="0"/>
- <xs:element name="quantity" type="xs:positiveInteger"/>
- <xs:element name="price" type="xs:decimal"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- </xs:sequence>
- <xs:attribute name="orderid" type="xs:string" use="required"/>
- </xs:complexType>
- </xs:element>
- </xs:schema>
4、參考文檔:
點擊打開鏈接
二、Java解析XML
l XML解析方式分為兩種:dom和sax
• dom:(Document Object Model, 即文檔對象模型) 是 W3C 組織推薦的處理 XML 的一種方式。
• sax: (Simple API for XML) 不是官方標准,但它是XML 社區事實上的標准,幾乎所有的 XML 解析器都支持它。
l XML解析器
• Crimson、Xerces 、Aelfred2
l XML解析開發包
• Jaxp、Jdom、dom4j
1、DOM解析
DOM是用與平台和語言無關的方式表示XML文檔的官方W3C標准。DOM是以層次結構組織的節點或信息片斷的集合。這個層次結構允許開發人員在樹中尋找特定信息。分析該結構通常需要加載整個文檔和構造層次結構,然后才能做任何工作。由於它是基於信息層次的,因而DOM被認為是基於樹或基於對象的。
DOM解析器把XML文檔轉化為一個包含其內容的樹,並可以對樹進行遍歷。
DOM是拉模型,在遍歷文檔時,會把感興趣的部分從讀取器中拉出,不需要引發事件,允許我們選擇性地處理節點。這大大提高了靈活性,以及整體效率。
JAXP(DOM解析)
l JAXP 開發包是J2SE的一部分,它由javax.xml、org.w3c.dom 、org.xml.sax 包及其子包組成
l 在 javax.xml.parsers 包中,定義了幾個工廠類,程序員調用這些工廠類,可以得到對xml文檔進行解析的 DOM 或 SAX的解析器對象。
1、java代碼顯例:
- <?xml version="1.0" encoding="UTF-8" standalone="no"?><exam>
- <student examid="111" idcard="123">
- <name>張三</name>
- <location>廣州</location>
- <grade>100</grade>
- </student>
- <student examid="444" idcard="333">
- <name>李四</name>
- <location>大連</location>
- <grade>97</grade>
- </student>
- <student examid="1111111" idcard="22222">
- <name>小毛</name>
- <location>廣州</location>
- <grade>23.0</grade>
- </student>
- <student examid="199" idcard="300">
- <grade>80.0</grade>
- <location>廣州</location>
- <name>鍾源茂</name>
- </student>
- </exam>
- package com.zhong.xml.parse;
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import javax.xml.parsers.DocumentBuilder;
- import javax.xml.parsers.DocumentBuilderFactory;
- import javax.xml.parsers.ParserConfigurationException;
- import javax.xml.transform.Transformer;
- 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.Document;
- import org.w3c.dom.Element;
- import org.w3c.dom.Node;
- import org.w3c.dom.NodeList;
- import org.xml.sax.SAXException;
- public class JaxpDemo {
- /**
- * @param args
- * @throws IOException
- */
- public static void main(String[] args) throws Exception {
- System.out.print("添加用戶:(a) ");
- System.out.print("刪除用戶:(b) ");
- System.out.println("查詢成績:(c)");
- System.out.print("請輸入操作類型:");
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
- String type = br.readLine();
- if("a".equals(type)){
- //添加用戶
- Student student = new Student();
- System.out.print("請輸入學生姓名:");
- String name = br.readLine();
- student.setName(name);
- System.out.print("請輸入學生准考證號:");
- String examid = br.readLine();
- student.setExamid(examid);
- System.out.print("請輸入學生身份證號:");
- String idcart = br.readLine();
- student.setIdcart(idcart);
- System.out.print("請輸入學生所在地:");
- String location = br.readLine();
- student.setLocation(location);
- System.out.print("請輸入學生成績:");
- String grade = br.readLine();
- student.setGrade(grade);
- add(student);
- System.out.println("------添加數據成功------");
- }else if("b".equals(type)){
- //刪除用戶
- System.out.print("請輸入刪除的學生姓名:");
- String name = br.readLine();
- delete(name);
- System.out.println("------已成功刪除學生信息------");
- }else if("c".equals(type)){
- //查詢成績
- System.out.print("請輸入查詢的學生准考證號:");
- String examid = br.readLine();
- Student student = find(examid);
- System.out.println("您查詢的學生信息為:");
- System.out.println(student);
- }else{
- System.out.println("對不起,您的操作有誤!!");
- }
- }
- private static Student find(String examid) throws Exception {
- Document document = getDocument();
- NodeList list = document.getElementsByTagName("student");
- for(int i=0;i<list.getLength();i++){
- Element element = (Element) list.item(i);
- String value = element.getAttribute("examid");
- if(examid.equals(value)){
- Student student = new Student();
- student.setExamid(examid);
- student.setIdcart(element.getAttribute("idcart"));
- student.setName(element.getElementsByTagName("name").item(0).getTextContent());
- student.setLocation(element.getElementsByTagName("location").item(0).getTextContent());
- student.setGrade(element.getElementsByTagName("grade").item(0).getTextContent());
- return student;
- }
- }
- return null;
- }
- private static void delete(String name) throws ParserConfigurationException, SAXException, IOException, TransformerException {
- Document document = getDocument();
- NodeList list = document.getElementsByTagName("name");
- for(int i=0;i<list.getLength();i++){
- Node node = list.item(i);
- if(node.getTextContent().equals(name)){
- node.getParentNode().getParentNode().removeChild(node.getParentNode());
- }
- }
- writeXml(document);
- }
- private static void add(Student student) throws Exception {
- Document document = getDocument();
- Element student_node = document.createElement("student");
- student_node.setAttribute("idcart", student.getIdcart());
- student_node.setAttribute("examid", student.getExamid());
- Node name = document.createElement("name");
- name.setTextContent(student.getName());
- Node location = document.createElement("location");
- location.setTextContent(student.getLocation());
- Node grade = document.createElement("grade");
- grade.setTextContent(student.getGrade());
- student_node.appendChild(name);
- student_node.appendChild(location);
- student_node.appendChild(grade);
- Element root = document.getDocumentElement();
- root.appendChild(student_node);
- writeXml(document);
- }
- //將內存中的數據保存到XML文件中
- private static void writeXml(Document document) throws TransformerException {
- DOMSource source = new DOMSource(document);
- StreamResult result = new StreamResult(new File("src/exam.xml"));
- TransformerFactory factory = TransformerFactory.newInstance();
- Transformer trans = factory.newTransformer();
- trans.transform(source, result);
- }
- //獲得操作xml文件的對象
- private static Document getDocument() throws ParserConfigurationException,
- SAXException, IOException {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();//得到創建 DOM 解析器的工廠。
- DocumentBuilder builder = factory.newDocumentBuilder();//得到 DOM 解析器對象。
- Document document = builder.parse(new File("src/exam.xml")); //得到代表整個文檔的 Document 對象
- Element e = document.getDocumentElement();
- return document;
- }
- }
- class Student{
- private String name;
- private String examid;
- private String idcart;
- private String location;
- private String grade;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getExamid() {
- return examid;
- }
- public void setExamid(String examid) {
- this.examid = examid;
- }
- public String getIdcart() {
- return idcart;
- }
- public void setIdcart(String idcart) {
- this.idcart = idcart;
- }
- public String getLocation() {
- return location;
- }
- public void setLocation(String location) {
- this.location = location;
- }
- public String getGrade() {
- return grade;
- }
- public void setGrade(String grade) {
- this.grade = grade;
- }
- public String toString(){
- return "姓名:" + name + ",身份證號:" + idcart + ",准考證號:" + examid + ",地區:" + location + ",成績:" + grade;
- }
- }
2、DOM的基本對象有5個:Document,Node,NodeList,Element和Attr。
2.1、Document對象
代表了整個XML的文檔,所有其它的Node,都以一定的順序包含在Document對象之內,排列成一個樹形的結構,程序員可以通過遍歷這顆樹來得到XML文檔的所有的內容,這也是對XML文檔操作的起點。我們總是先通過解析XML源文件而得到一個Document對象,然后再來執行后續的操作。此外,Document還包含了創建其它節點的方法,比如createAttribut()用來創建一個Attr對象。它所包含的主要的方法有:
createAttribute(String):用給定的屬性名創建一個Attr對象,並可在其后使用setAttributeNode方法來放置在某一個Element對象上面。
createElement(String):用給定的標簽名創建一個Element對象,代表XML文檔中的一個標簽,然后就可以在這個Element對象上添加屬性或進行其它的操作。
createTextNode(String):用給定的字符串創建一個Text對象,Text對象代表了標簽或者屬性中所包含的純文本字符串。如果在一個標簽內沒有其它的標簽,那么標簽內的文本所代表的Text對象是這個Element對象的唯一子對象。
getElementsByTagName(String):返回一個NodeList對象,它包含了所有給定標簽名字的標簽。
getDocumentElement():返回一個代表這個DOM樹的根節點的Element對象,也就是代表XML文檔根元素的那個對象。
2.2、Node對象
是DOM結構中最為基本的對象,代表了文檔樹中的一個抽象的節點。在實際使用的時候,很少會真正的用到Node這個對象,而是用到諸如Element、Attr、Text等Node對象的子對象來操作文檔。Node對象為這些對象提供了一個抽象的、公共的根。雖然在Node對象中定義了對其子節點進行存取的方法,但是有一些Node子對象,比如Text對象,它並不存在子節點,這一點是要注意的。Node對象所包含的主要的方法有:
appendChild(org.w3c.dom.Node):為這個節點添加一個子節點,並放在所有子節點的最后,如果這個子節點已經存在,則先把它刪掉再添加進去。
getFirstChild():如果節點存在子節點,則返回第一個子節點,對等的,還有getLastChild()方法返回最后一個子節點。
getNextSibling():返回在DOM樹中這個節點的下一個兄弟節點,對等的,還有getPreviousSibling()方法返回其前一個兄弟節點。
getNodeName():根據節點的類型返回節點的名稱。
getNodeType():返回節點的類型。
getNodeValue():返回節點的值。
hasChildNodes():判斷是不是存在有子節點。
hasAttributes():判斷這個節點是否存在有屬性。
getOwnerDocument():返回節點所處的Document對象。
insertBefore(org.w3c.dom.Node new,org.w3c.dom.Node ref):在給定的一個子對象前再插入一個子對象。
removeChild(org.w3c.dom.Node):刪除給定的子節點對象。
replaceChild(org.w3c.dom.Node new,org.w3c.dom.Node old):用一個新的Node對象代替給定的子節點對象。
2.3、NodeList對象
顧名思義,就是代表了一個包含了一個或者多個Node的列表。可以簡單的把它看成一個Node的數組,我們可以通過方法來獲得列表中的元素:
getLength():返回列表的長度。
item(int):返回指定位置的Node對象。
2.4、Element對象
代表的是XML文檔中的標簽元素,繼承於Node,亦是Node的最主要的子對象。在標簽中可以包含有屬性,因而Element對象中有存取其屬性的方法,而任何Node中定義的方法,也可以用在Element對象上面。
getElementsByTagName(String):返回一個NodeList對象,它包含了在這個標簽中其下的子孫節點中具有給定標簽名字的標簽。
getTagName():返回一個代表這個標簽名字的字符串。
getAttribute(String):返回標簽中給定屬性名稱的屬性的值。在這兒需要主要的是,應為XML文檔中允許有實體屬性出現,而這個方法對這些實體屬性並不適用。這時候需要用到getAttributeNodes()方法來得到一個Attr對象來進行進一步的操作。
getAttributeNode(String):返回一個代表給定屬性名稱的Attr對象。
2.5、Attr對象
代表了某個標簽中的屬性。Attr繼承於Node,但是因為Attr實際上是包含在Element中的,它並不能被看作是Element的子對象,因而在DOM中Attr並不是DOM樹的一部分,所以Node中的getParentNode(),getPreviousSibling()和getNextSibling()返回的都將是null。也就是說,Attr其實是被看作包含它的Element對象的一部分,它並不作為DOM樹中單獨的一個節點出現。這一點在使用的時候要同其它的Node子對象相區別。
2、SAX解析
SAX是Simple API forXML的縮寫,它並不是由W3C官方所提出的標准,可以說是“民間”的事實標准。實際上,它是一種社區性質的討論產物。雖然如此,在XML中對SAX的應用絲毫不比DOM少,幾乎所有的XML解析器都會支持它。
與DOM比較而言,SAX是一種輕量型的方法。我們知道,在處理DOM的時候,我們需要讀入整個的XML文檔,然后在內存中創建DOM樹,生成DOM樹上的每個Node對象。當文檔比較小的時候,這不會造成什么問題,但是一旦文檔大起來,處理DOM就會變得相當費時費力。特別是其對於內存的需求,也將是成倍的增長,以至於在某些應用中使用DOM是一件很不划算的事(比如在applet中)。這時候,一個較好的替代解決方法就是SAX。
SAX在概念上與DOM完全不同。首先,不同於DOM的文檔驅動,它是事件驅動的,也就是說,它並不需要讀入整個文檔,而文檔的讀入過程也就是SAX的解析過程。所謂事件驅動,是指一種基於回調(callback)機制的程序運行方法。(如果你對Java新的代理事件模型比較清楚的話,就會很容易理解這種機制了)
回調:由我們在組件中定義,而不由我們調用,由容器或框架調用
SAX是推模型,它是一種靠事件驅動的模型。當它每發現一個節點就引發一個事件,而我們需要編寫這些事件的處理程序。這樣的做法很麻煩,且不靈活。
一、StAX 解析
針對於XML的流式API(StAX),是在2004年3月的JSR 173規范中引入,這是一種針對XML的流式拉分析API。StAX是JDK 6.0提供的一種新特征。
一個推模型分析器不斷地生成事件,直到XML文檔被完全分析結束。但是,拉分析由應用程序進行調整;因此,分析事件是由應用程序生成的。這意味着,使用StaX,你可以推遲分析-在分析時跳過元素並且分析多個文檔。在使用DOM API的時候,你必須把整個的XML文檔分析成一棵DOM結構,這樣也就降低了分析效率。而借助於StAX,在分析XML文檔時生成分析事件。
二、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許可證變體下發布的開放源碼。
三、DOM4J
http://dom4j.sourceforge.NET
雖然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是一個非常非常優秀的JavaXML API,具有性能優異、功能強大和極端易用使用的特點,同時它也是一個開放源代碼的軟件。如今你可以看到越來越多的Java軟件都在使用DOM4J來讀寫XML,特別值得一提的是連Sun的JAXM也在用DOM4J.
代碼顯例:
用dom4j解析xml要導入dom4j.jar
下載:點擊打開鏈接
- <?xml version="1.0" encoding="UTF-8"?>
- <exam>
- <student examid="111" idcard="123">
- <name>張三</name>
- <location>廣州</location>
- <grade>100</grade>
- </student>
- <student examid="444" idcard="333">
- <name>李四</name>
- <location>大連</location>
- <grade>97</grade>
- </student>
- <student examid="1111111" idcard="22222">
- <name>小毛</name>
- <location>廣州</location>
- <grade>23.0</grade>
- </student>
- <student examid="199" idcard="300">
- <grade>80.0</grade>
- <location>廣州</location>
- <name>鍾源茂</name>
- </student>
- </exam>
- package cn.zhong.dao;
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.util.Iterator;
- import java.util.List;
- import javax.xml.parsers.ParserConfigurationException;
- import org.dom4j.Document;
- import org.dom4j.DocumentException;
- import org.dom4j.Element;
- import org.dom4j.io.SAXReader;
- import org.dom4j.io.XMLWriter;
- import org.junit.Test;
- import org.xml.sax.SAXException;
- public class Dom4j_demo {
- public static void main(String[] args) throws IOException,
- ParserConfigurationException, SAXException, DocumentException {
- System.out.println("添加學生 (a) 查找學生 (b) 刪除學生 (c)");
- System.out.print("請輸入想要的操作:");
- BufferedReader buf = new BufferedReader(
- new InputStreamReader(System.in));
- String value = buf.readLine();
- if (value.equalsIgnoreCase("a")) {
- try {
- System.out.print("請輸入學生姓名:");
- String name = buf.readLine();
- System.out.print("請輸入學生准考證號:");
- String examid = buf.readLine();
- System.out.print("請輸入學生身份證號:");
- String idcard = buf.readLine();
- System.out.print("請輸入學生所在地:");
- String location = buf.readLine();
- System.out.print("請輸入學生成績:");
- String grade = buf.readLine();
- Student student = new Student();
- student.setExamid(examid);
- student.setGrade(Double.parseDouble(grade));
- student.setIdcard(idcard);
- student.setLocation(location);
- student.setName(name);
- // StudentDaoByJaxp sd = new StudentDaoByJaxp();
- // sd.appUser(student);
- Dom4j_demo dj = new Dom4j_demo();
- dj.appUser(student);
- System.out.println("恭喜你,添加成功");
- dj.appUser(student);
- } catch (IOException e) {
- System.out.println("輸入有誤,添加失敗,請重新輸入");
- }
- } else if (value.equalsIgnoreCase("b")) {
- System.out.print("請輸入想查找的學生准考證號:");
- String examid = buf.readLine();
- Dom4j_demo dj = new Dom4j_demo();
- Student s = dj.selectUser(examid);
- if (s != null) {
- System.out.println("你要查找的學生的信息如下:");
- System.out.println("姓名:" + s.getName());
- System.out.println("准考證號:" + s.getExamid());
- System.out.println("身份證號:" + s.getIdcard());
- System.out.println("所在地:" + s.getLocation());
- System.out.println("成績:" + s.getGrade());
- } else {
- System.out.println("你所查找的學生不存在");
- }
- } else if (value.equalsIgnoreCase("c")) {
- try {
- System.out.print("請輸入想刪除的學生姓名:");
- String name = buf.readLine();
- Dom4j_demo dj = new Dom4j_demo();
- dj.deleteUser(name);
- System.out.println("恭喜你,刪除成功");
- } catch (Exception e) {
- System.out.println("刪除失敗,請重新來過");
- }
- } else {
- System.out.println("請輸入正確的指令");
- }
- }
- // 增加學生
- @Test
- public void appUser(Student student) {
- try {
- Document document = getDocument();
- Element rootNode = document.getRootElement();
- Element sNode = rootNode.addElement("student");
- sNode.addAttribute("examid", student.getExamid());
- sNode.addAttribute("idcard", student.getIdcard());
- sNode.addElement("name").setText(student.getName());
- sNode.addElement("location").setText(student.getLocation());
- sNode.addElement("grade").setText(student.getGrade() + "");
- write2Xml(document);
- } catch (Exception e) {
- throw new RuntimeException();
- }
- }
- // 查找學生
- @Test
- public Student selectUser(String examid) throws DocumentException {
- Document document = getDocument();
- Element e = (Element) document.selectSingleNode("//student[@examid='"
- + examid + "']");
- if (e != null) {
- Student s = new Student();
- s.setExamid(e.attributeValue("examid"));
- s.setIdcard(e.attributeValue("idcard"));
- s.setName(e.element("name").getText());
- s.setLocation(e.element("location").getText());
- s.setGrade(Double.parseDouble(e.element("grade").getText()));
- return s;
- } else {
- return null;
- }
- /*
- * // List list=document.getRootElement().selectNodes("student"); List
- * list=document.selectNodes("//student");//使用xpath Iterator
- * it=list.iterator(); while(it.hasNext()) { Element e=(Element)
- * it.next(); String value=e.attributeValue("examid");
- * if(value.equals(examid)) { Student s = new Student();
- * s.setExamid(e.attributeValue("examid"));
- * s.setIdcard(e.attributeValue("idcard"));
- *
- * s.setName(e.element("name").getText());
- * s.setLocation(e.element("location").getText());
- * s.setGrade(Double.parseDouble(e.element("grade").getText()));
- *
- * return s; } }
- *
- * return null;
- */
- }
- // 刪除學生
- @Test
- public void deleteUser(String name) {
- try {
- Document document = getDocument();
- List list = document.selectNodes("//name");
- Iterator it = list.iterator();
- // Element nameNode1=(Element) it.next();
- // System.out.println(nameNode1.getText());
- while (it.hasNext()) {
- Element nameNode = (Element) it.next();
- String value = nameNode.getText();
- if (value.equals(name)) {
- // System.out.println(nameNode.getText());
- nameNode.getParent().getParent()
- .remove(nameNode.getParent());
- write2Xml(document);
- return;
- }
- }
- throw new RuntimeException("刪除失敗");
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- // 獲得操作xml的對象 獲得document對象
- public Document getDocument() throws DocumentException {
- SAXReader reader = new SAXReader();
- Document document = reader.read(new File("src//student.xml"));
- /*
- * 2.解析XML形式的文本,得到document對象.
- * String text ="<members></members>";
- * Document document =DocumentHelper.parseText(text);
- *
- * 3.主動創建document對象.
- * Document document =DocumentHelper.createDocument();
- * //創建根節點 Element root =document.addElement("members");
- */
- return document;
- }
- // 將內存中的內容寫入xml
- public void write2Xml(Document document) throws IOException {
- //1.文檔中全為英文,不設置編碼,直接寫入的形式
- XMLWriter writer = new XMLWriter(new FileOutputStream("src//student.xml"));
- writer.write(document);
- writer.close();
- // 2.文檔中含有中文,設置編碼格式寫入的形式
- // OutputFormat format = OutputFormat.createPrettyPrint();// 指定XML編碼
- // format.setEncoding("GBK");
- // XMLWriter writer = new XMLWriter(newFileWriter("output.xml"),format);
- // writer.write(document);writer.close();
- }
- }
- class Student {
- /*
- * <student examid="111" idcard="123" > <name>張三</name>
- * <location>廣州</location> <grade>100</grade> </student>
- */
- private String examid;
- private String idcard;
- private String name;
- private String location;
- private double grade;
- public String getExamid() {
- return examid;
- }
- public void setExamid(String examid) {
- this.examid = examid;
- }
- public String getIdcard() {
- return idcard;
- }
- public void setIdcard(String idcard) {
- this.idcard = idcard;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getLocation() {
- return location;
- }
- public void setLocation(String location) {
- this.location = location;
- }
- public double getGrade() {
- return grade;
- }
- public void setGrade(double grade) {
- this.grade = grade;
- }
- }
3、DMO與SAX的區別
一、DOM:拉模型,把整個文檔加載到內存中
優點:整個文檔樹在內存中,便於操作;支持刪除、修改、重新排列等多種功能;
缺點:將整個文檔調入內存(包括無用的節點),浪費時間和空間;
使用場合:一旦解析了文檔還需多次訪問這些數據;硬件資源充足(內存、CPU)
二、SAX:推模型,事件驅動編程,基於回調SAX ,事件驅動。當解析器發現元素開始、元素結束、文本、文檔的開始或結束等時,發送事件,程序員編寫響應這些事件的代碼,保存數據。
優點:不用事先調入整個文檔,占用資源少;
缺點:不是持久的;事件過后,若沒保存數據,那么數據就丟了;無狀態性;從事件中只能得到文本,但不知該文本屬於哪個元素;
使用場合:數據量較大的XML文檔,占用內存高,機器內存少,無法一次加載XML到內存;只需XML文檔的少量內容,很少回頭訪問;
三、JDOM:為減少DOM、SAX的編碼量,出現了JDOM;
優點:20-80原則,極大減少了代碼量,提供常用API減少重復勞動
使用場合:要實現的功能簡單,如解析、創建等Java程序
但在底層,JDOM還是使用SAX(最常用)、DOM
性能比較
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流被讀入時,會有部分文檔暫時隱藏在內存中)。