JDOM是一個開源項目,它基于樹型結構,利用純JAVA的技術對XML文檔實現解析、生成、序列化以及多種操作。
JDOM 直接為JAVA編程服務。它利用更為強有力的JAVA語言的諸多特性(方法重載、集合概念以及映射),把SAX和DOM的功能有效地結合起來。
Jdom是用Java語言讀、寫、操作XML的新API函數。Jason Hunter 和 Brett McLaughlin公開發布了它的1.0版本。在直覺、簡單和高效的前提下,這些API函數被最大限度的優化。在接下來的篇幅里將介紹怎么用Jdom去讀寫一個已經存在的XML文檔。
在使用設計上盡可能地隱藏原來使用XML過程中的復雜性。利用JDOM處理XML文檔將是一件輕松、簡單的事。
JDOM 在2000年的春天被Brett McLaughlin和Jason Hunter開發出來,以彌補DOM及SAX在實際應用當中的不足之處。
這些不足之處主要在于SAX沒有文檔修改、隨機訪問以及輸出的功能,而對于DOM來說,JAVA程序員在使用時來用起來總覺得不太方便。
DOM的缺點主要是來自于由于Dom是一個接口定義語言(IDL),它的任務是在不同語言實現中的一個最低的通用標準,并不是為JAVA特別設計的。JDOM的最新版本為JDOM Beta 9。最近JDOM被收錄到JSR-102內,這標志著JDOM成為了JAVA平臺組成的一部分。
在 JDOM 中,XML 元素就是 Element 的實例,XML 屬性就是 Attribute 的實例,XML 文檔本身就是 Document 的實例。
因為 JDOM 對象就是像 Document、Element 和 Attribute 這些類的直接實例,因此創建一個新 JDOM 對象就如在 Java 語言中使用 new 操作符一樣容易。JDOM 的使用是直截了當的。
JDOM 使用標準的 Java 編碼模式。只要有可能,它使用 Java new 操作符而不故弄玄虛使用復雜的工廠化模式,使對象操作即便對于初學用戶也很方便。
一、JDOM包概覽
JDOM是由以下幾個包組成的
org.jdom包含了所有的xml文檔要素的java類
org.jdom.adapters包含了與dom適配的java類
org.jdom.filter包含了xml文檔的過濾器類
org.jdom.input包含了讀取xml文檔的類
org.jdom.output包含了寫入xml文檔的類
org.jdom.transform包含了將jdomxml文檔接口轉換為其他xml文檔接口
org.jdom.xpath包含了對xml文檔xpath操作的類
二、JDOM類說明
1、org.JDOM這個包里的類是你J解析xml文件后所要用到的所有數據類型。
Attribute
CDATA
Coment
DocType
Document
Element
EntityRef
Namespace
ProscessingInstruction
Text
2、org.JDOM.transform在涉及xslt格式轉換時應使用下面的2個類
JDOMSource
JDOMResult
org.JDOM.input
3、輸入類,一般用于文檔的創建工作
SAXBuilder
DOMBuilder
ResultSetBuilder
4、org.JDOM.output輸出類,用于文檔轉換輸出
XMLOutputter
SAXOutputter
DomOutputter
JTreeOutputter
使用前注意事項:
1.JDOM對于JAXP以及TRax的支持
JDOM支持JAXP1.1:你可以在程序中使用任何的parser工具類,默認情況下是JAXP的parser。
制定特別的parser可用如下形式
SAXBuilderparser
=newSAXBuilder("org.apache.crimson.parser.XMLReaderImpl");
Documentdoc=parser.build("http://www.cafeconleche.org/");
//workwiththedocument...
JDOM也支持TRaX:XSLT可通過JDOMSource以及JDOMResult類來轉換(參見以后章節)
2.注意在JDOM里文檔(Document)類由org.JDOM.Document來表示。這要與org.w3c.dom中的Document區別開,這2種格式如何轉換在后面會說明。
以下如無特指均指JDOM里的Document。
三、JDOM主要使用方法
1.Ducument類
(1)Document的操作方法:
Elementroot=newElement("GREETING");
Documentdoc=newDocument(root);
root.setText("HelloJDOM!");
或者簡單的使用Documentdoc=newDocument(newElement("GREETING").setText("HelloJDOM!t"));
這點和DOM不同。Dom則需要更為復雜的代碼,如下:
DocumentBuilderFactoryfactory=DocumentBuilderFactory.newInstance();
DocumentBuilderbuilder=factory.newDocumentBuilder();
Documentdoc=builder.newDocument();
Elementroot=doc.createElement("root");
Texttext=doc.createText("Thisistheroot");
root.appendChild(text);
doc.appendChild(root);
注意事項:JDOM不允許同一個節點同時被2個或多個文檔相關聯,要在第2個文檔中使用原來老文檔中的節點的話。首先需要使用detach()把這個節點分開來。
(2)從文件、流、系統ID、URL得到Document對象:
DOMBuilderbuilder=newDOMBuilder();
Documentdoc=builder.build(newFile("jdom_test.xml"));
SAXBuilderbuilder=newSAXBuilder();
Documentdoc=builder.build(url);
在新版本中DOMBuilder已經Deprecated掉DOMBuilder.builder(url),用SAX效率會比較快。
這里舉一個小例子,為了簡單起見,使用String對象直接作為xml數據源:
PublicjdomTest(){
StringtextXml=null;
textXml="";
textXml=textXml+
"aaabbbcccddd";
textXml=textXml+"";
SAXBuilderbuilder=newSAXBuilder();
Documentdoc=null;
Readerin=newStringReader(textXml);
try{
doc=builder.build(in);
Elementroot=doc.getRootElement();
Listls=root.getChildren();//注意此處取出的是root節點下面的一層的Element集合
for(Iteratoriter=ls.iterator();iter.hasNext();){
Elementel=(Element)iter.next();
if(el.getName().equals("to")){
System.out.println(el.getText());
}
}
}
catch(IOExceptionex){
ex.printStackTrace();
}
catch(JDOMExceptionex){
ex.printStackTrace();
}
}
(3)DOM的document和JDOM的Document之間的相互轉換使用方法,簡單!
DOMBuilderbuilder=newDOMBuilder();
org.jdom.DocumentjdomDocument=builder.build(domDocument);
DOMOutputterconverter=newDOMOutputter();//workwiththeJDOMdocument…
org.w3c.dom.DocumentdomDocument=converter.output(jdomDocument);
//workwiththeDOMdocument…
2.XML文檔輸出
XMLOutPutter類:
JDOM的輸出非常靈活,支持很多種io格式以及風格的輸出
Documentdoc=newDocument(...);
XMLOutputteroutp=newXMLOutputter();
outp.output(doc,fileOutputStream);//Rawoutput
outp.setTextTrim(true);//Compressedoutput
outp.output(doc,socket.getOutputStream());
outp.setIndent("");//Prettyoutput
outp.setNewlines(true);
outp.output(doc,System.out);
詳細請參閱最新的JDOMAPI手冊
3.Element類:
(1)瀏覽Element樹
Elementroot=doc.getRootElement();//獲得根元素element
ListallChildren=root.getChildren();//獲得所有子元素的一個list
ListnamedChildren=root.getChildren("name");//獲得指定名稱子元素的list
Elementchild=root.getChild("name");//獲得指定名稱的第一個子元素
JDOM給了我們很多很靈活的使用方法來管理子元素(這里的List是java.util.List)
ListallChildren=root.getChildren();
allChildren.remove(3);//刪除第四個子元素
allChildren.removeAll(root.getChildren("jack"));//刪除叫“jack”的子元素
root.removeChildren("jack");//便捷寫法
allChildren.add(newElement("jane"));//加入
root.addContent(newElement("jane"));//便捷寫法
allChildren.add(0,newElement("first"));
(2)移動Elements:
在JDOM里很簡單
Elementmovable=newElement("movable");
parent1.addContent(movable);//place
parent1.removeContent(movable);//remove
parent2.addContent(movable);//add
在Dom里
Elementmovable=doc1.createElement("movable");
parent1.appendChild(movable);//place
parent1.removeChild(movable);//remove
parent2.appendChild(movable);//出錯!
補充:糾錯性
JDOM的Element構造函數(以及它的其他函數)會檢查element是否合法。
而它的add/remove方法會檢查樹結構,檢查內容如下:
1.在任何樹中是否有回環節點
2.是否只有一個根節點
3.是否有一致的命名空間(Namespaces)
(3)Element的text內容讀取
Acooldemo
//Thetextisdirectlyavailable
//Returns"\nAcooldemo\n"
Stringdesc=element.getText();
//There'saconvenientshortcut
//Returns"Acooldemo"
Stringdesc=element.getTextTrim();
(4)Elment內容修改
element.setText("Anewdescription");
3.可正確解釋特殊字符
element.setText("
四、JDOM的應用
(一)、XML文檔創建
我們由零開始利用JDOM生成一個XML文檔。最后的結果(樣本文檔)看起來象這樣:
kingwong
87654321
1.以 MyInfo 為根元素創建文檔
Element rootElement = new Element("MyInfo");//所有的XML元素都是 Element 的實例。根元素也不例外:)
Document myDocument = new Document(rootElement);//以根元素作為參數創建Document對象。一個Document只有一個根,即root元素。
2.給根元素添加屬性
Attribute rootAttri = new Attribute("comment","introduce myself");//創建名為 commnet,值為 introduce myself 的屬性。
rootElement.setAttribute(rootAttri);//將剛創建的屬性添加到根元素。
這兩行代碼你也可以合成一行來寫,象這樣:
rootElement.setAttribute(new Attribute("comment","introduce myself"));
或者
rootElement.setAttribute("comment","introduce myself");
3.添加元素和子元素
JDOM里子元素是作為 content(內容)添加到父元素里面去的,所謂content就是類似上面樣本文檔中之間的東東,即kingwong。羅嗦了點是吧:)
Element nameElement = new Element("name");//創建 name 元素
nameElement.addContent("kingwong");//將kingwong作為content添加到name元素
rootElement.addContent(nameElement);//將name元素作為content添加到根元素
這三行你也可以合為一句,象這樣:
rootElement.addContent((Content)(new Element("name").addContent("kingwong")));//因為addContent(Content child)方法返回的是一個Parent接口,而Element類同時繼承了Content類和實現了Parent接口,所以我們把它造型成Content。
我們用同樣的方法添加帶屬性的子元素
rootElement.addContent(new Element("sex").setAttribute("value","male"));//注意這里不需要轉型,因為addAttribute(String name,String value)返回值就是一個 Element。
同樣的,我們添加元素到根元素下,用法上一樣,只是稍微復雜了一些:
rootElement.addContent((Content)(new Element("contact").addContent((Content)(new Element("telephone").addContent("87654321")))));
如果你對這種簡寫形式還不太習慣,你完全可以分步來做,就象本節剛開始的時候一樣。事實上如果層次比較多,寫成分步的形式更清晰些,也不容易出錯。
4.刪除子元素
這個操作比較簡單:
rootElement.removeChild("sex");//該方法返回一個布爾值
到目前為止,我們學習了一下JDOM文檔生成操作。上面建立了一個樣本文檔,可是我們怎么知道對不對呢?因此需要輸出來看一下。我們將JDOM生成的文檔輸出到控制臺,使用 JDOM 的 XMLOutputter 類。
5. 將 JDOM 轉化為 XML 文本
XMLOutputter xmlOut = new XMLOutputter(" ",true);
try {
xmlOut.output(myDocument,System.out);
} catch (IOException e) {
e.printStackTrace();
}
XMLOutputter 有幾個格式選項。這里我們已指定希望子元素從父元素縮進兩個空格,并且希望元素間有空行。
new XMLOutputter(java.lang.String indent, boolean newlines)這個方法在最新版本中已經不建議使用。JDOM有一個專門的用來定義格式化輸出的類:org.jdom.output.Format,如果你沒有特殊的要求,有時候使用里面的幾個靜態方法(應該可以說是預定義格式)如 getPrettyFormat()就可以了。我們把上面的輸出格式稍微改一下,就象這樣:
XMLOutputter xmlOut = new XMLOutputter(Format.getPrettyFormat());
6.將JDOM文檔轉化為其他形式
XMLOutputter 還可輸出到 Writer 或 OutputStream。為了輸出JDOM文檔到一個文本文件,我們可以這樣做:
FileWriter writer = new FileWriter("/some/directory/myFile.xml");
outputter.output(myDocument, writer);
writer.close();
XMLOutputter 還可輸出到字符串,以便程序后面進行再處理:
Strng outString = xmlOut.outputString(myDocument);
當然,在輸出的時候你不一定要輸出所有的整個文檔,你可以選擇元素進行輸出:
xmlOut.output(rootElement.getChild("name"),System.out);
一句話,JDOM非常靈活方便!如果你想進一步研究JDOM,請到官方網站去看一看:http://www.jdom.org
本節示例源碼:
package com.cyberobject.study;
import java.io.IOException;
import org.jdom.Attribute;
import org.jdom.Content;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
/**
* @author kingwong
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class TestJDOM {
public static void main(String[] args)
{
Element rootElement = new Element("MyInfo");
Document myDocument = new Document(rootElement);
// Attribute rootAttri = new Attribute("comment","introduce myself");
// rootElement.setAttribute(rootAttri);
rootElement.setAttribute("comment","introduce myself");
//rootElement.setAttribute(new Attribute("comment","introduce myself"));
// Element sexElement = new Element("sex");
// rootElement.addContent(sexElement);
// Element nameElement = new Element("name");
// nameElement.addContent("kingwong");
// rootElement.addContent(nameElement);
rootElement.addContent((Content)(new Element("name").addContent("kingwong")));
rootElement.addContent(new Element("sex").setAttribute("value","male"));
rootElement.addContent((Content)(new Element("contract").addContent((Content)(new Element("telephone").addContent("87654321")))));
rootElement.removeChild("sex");
XMLOutputter xmlOut = new XMLOutputter(Format.getPrettyFormat());
try {
xmlOut.output(myDocument,System.out);
//xmlOut.output(rootElement.getChild("name"),System.out);
//String outString = xmlOut.outputString(myDocument);
} catch (IOException e) {
e.printStackTrace();
}
}
}
(二)、XML文檔解析
JDOM 不光可以很方便的建立XML文檔,它的另一個用處是它能夠讀取并操作現有的 XML 數據。
JDOM的解析器在org.jdom.input.*這個包里,其中的DOMBuilder的功能是將DOM模型的Document解析成JDOM模型的Document;SAXBuilder的功能是從文件或流中解析出符合JDOM模型的XML樹。由于我們經常要從一個文件里讀取數據,因此我們應該采用后者作為解析工具。
解析一個xml文檔,基本可以看成以下幾個步驟:
1.實例化一個合適的解析器對象
本例中我們使用SAXBuilder:
SAXBuilder sb = new SAXBuilder();
2.以包含XML數據的文件為參數,構建一個文檔對象myDocument
Document myDocument = sb.build(/some/directory/myFile.xml);
3.獲到根元素
Element rootElement = myDocument.getRootElement();
一旦你獲取了根元素,你就可以很方便地對它下面的子元素進行操作了,下面對Element對象的一些常用方法作一下簡單說明:
getChild("childname") 返回指定名字的子節點,如果同一級有多個同名子節點,則只返回第一個;如果沒有返回null值。
getChildren("childname") 返回指定名字的子節點List集合。這樣你就可以遍歷所有的同一級同名子節點。
getAttributeValue("name") 返回指定屬性名字的值。如果沒有該屬性則返回null,有該屬性但是值為空,則返回空字符串。
getChildText("childname") 返回指定子節點的內容文本值。
getText() 返回該元素的內容文本值。
還有其他沒有羅列出來的方法,如果需要的話,可以隨時查閱JDOM的在線文檔:http://www.jdom.org/docs/apidocs/index.html。當然你可以在你需要的地方添加、刪除元素操作,還記得上面的創建XML的方法嗎?呵呵~~~
學習新東東還是從實例學起最為快捷,下面簡單舉個例子,就以上面的XML樣本代碼來學習JDOM的XML解析。本例中讀取了樣本XML文件里一些屬性和content,最后我們還在contact元素里插入了一個新元素wanghua@cyberobject.com" />。盡管我們實現了對于XML的基本操作,細心的朋友可能會
有疑問:如果XML文檔的層次稍微復雜一些,如果嵌套多達幾十上百層的話(開個玩笑),如果靠這樣從根元素一級一級地通過getChild("childname")來訪問子元素的話,將會非常痛苦!是的,的確是這樣,但是我們有另一個有力的工具XPath,為什么不用呢?這是后話!先賣個關子(手敲累啦,下回吧,呵呵)。
/*
* Created on 2004-8-21
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package com.cyberobject.study;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
/**
* @author kingwong
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class TestJDOM2 {
public static void main(String[] args){
SAXBuilder sb = new SAXBuilder();
try
{
Document doc = sb.build("myFile.xml");
Element root = doc.getRootElement();
String str1 = root.getAttributeValue("comment");
System.out.println("Root Element's comment attribute is : " + str1);
String str2 = root.getChild("sex").getAttributeValue("value");
System.out.println("sex Element's value attribute is : " + str2);
String str3 = root.getChildText("name");
System.out.println("name Element's content is :" + str3);
String str4 = root.getChild("contact").getChildText("telephone");
System.out.println("contact Element's telephone subelement content is : " + str4 + "\n");
Element inputElement = root.getChild("contact");
inputElement.addContent(new Element("email").setAttribute("value","wanghua@cyberobject.com"));
XMLOutputter xmlOut = new XMLOutputter(Format.getPrettyFormat());
String outStr = xmlOut.outputString(root);
System.out.println(outStr);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}