http://www.rjxz.cn/Article.asp?id=498
?Dom4j的使用
最近在學(xué)習(xí)JAVA讀寫(xiě)XML。網(wǎng)上找到這篇文章。
轉(zhuǎn)貼:http://www.cublog.cn/opera/showart.php?blogid=13995&id=89783
Dom4j的使用
Dom4j 使用簡(jiǎn)介
作者:冰云 icecloud(AT)sina.com
時(shí)間:2003.12.15
?
版權(quán)聲明:
本文由冰云完成,首發(fā)于CSDN,未經(jīng)許可,不得使用于任何商業(yè)用途。
文中代碼部分引用自DOM4J文檔。
歡迎轉(zhuǎn)載,但請(qǐng)保持文章及版權(quán)聲明完整。
如需聯(lián)絡(luò)請(qǐng)發(fā)郵件:icecloud(AT)sina.com
?
??? DOM4J是dom4j.org出品的一個(gè)開(kāi)源XML解析包,它的網(wǎng)站中這樣定義:
Dom4j is an easy to use, open source library for working with XML, XPath and XSLT on the Java platform using the Java Collections Framework and with full support for DOM, SAX and JAXP.
Dom4j是一個(gè)易用的、開(kāi)源的庫(kù),用于XML,XPath和XSLT。它應(yīng)用于Java平臺(tái),采用了Java集合框架并完全支持DOM,SAX和JAXP。
DOM4J使用起來(lái)非常簡(jiǎn)單。只要你了解基本的XML-DOM模型,就能使用。然而他自己帶的指南只有短短一頁(yè)(html),不過(guò)說(shuō)的到挺全。國(guó)內(nèi)的中文資料很少。因而俺寫(xiě)這個(gè)短小的教程方便大家使用,這篇文章僅談及基本的用法,如需深入的使用,請(qǐng)……自己摸索或查找別的資料。
之前看過(guò)IBM developer社區(qū)的文章(參見(jiàn)附錄),提到一些XML解析包的性能比較,其中DOM4J的性能非常出色,在多項(xiàng)測(cè)試中名列前茅。(事實(shí)上DOM4J的官方文檔中也引用了這個(gè)比較)所以這次的項(xiàng)目中我采用了DOM4J作為XML解析工具。
在國(guó)內(nèi)比較流行的是使用JDOM作為解析器,兩者各擅其長(zhǎng),但DOM4J最大的特色是使用大量的接口,這也是它被認(rèn)為比JDOM靈活的主要原因。大師不是說(shuō)過(guò)么,“面向接口編程”。目前使用DOM4J的已經(jīng)越來(lái)越多。如果你善于使用JDOM,不妨繼續(xù)用下去,只看看本篇文章作為了解與比較,如果你正要采用一種解析器,不如就用DOM4J吧。
它的主要接口都在org.dom4j這個(gè)包里定義:
Attribute?Attribute定義了XML的屬性
Branch?Branch為能夠包含子節(jié)點(diǎn)的節(jié)點(diǎn)如XML元素(Element)和文檔(Docuemnts)定義了一個(gè)公共的行為,
CDATA?CDATA 定義了XML CDATA 區(qū)域
CharacterData?CharacterData是一個(gè)標(biāo)識(shí)借口,標(biāo)識(shí)基于字符的節(jié)點(diǎn)。如CDATA,Comment, Text.
Comment?Comment 定義了XML注釋的行為
Document?定義了XML文檔
DocumentType?DocumentType 定義XML DOCTYPE聲明
Element?Element定義XML 元素
ElementHandler?ElementHandler定義了 Element 對(duì)象的處理器
ElementPath?被 ElementHandler 使用,用于取得當(dāng)前正在處理的路徑層次信息
Entity?Entity定義 XML entity
Node?Node為所有的dom4j中XML節(jié)點(diǎn)定義了多態(tài)行為
NodeFilter?NodeFilter 定義了在dom4j節(jié)點(diǎn)中產(chǎn)生的一個(gè)濾鏡或謂詞的行為(predicate)
ProcessingInstruction?ProcessingInstruction 定義 XML 處理指令.
Text?Text 定義XML 文本節(jié)點(diǎn).
Visitor?Visitor 用于實(shí)現(xiàn)Visitor模式.
XPath?XPath 在分析一個(gè)字符串后會(huì)提供一個(gè)XPath 表達(dá)式
看名字大致就知道它們的涵義如何了。
要想弄懂這套接口,關(guān)鍵的是要明白接口的繼承關(guān)系:
interface java.lang.Cloneable
interface org.dom4j.Node
?
interface org.dom4j.Attribute
interface org.dom4j.Branch
?
?
interface org.dom4j.Document
interface org.dom4j.Element
interface org.dom4j.CharacterData
interface org.dom4j.CDATA
interface org.dom4j.Comment
interface org.dom4j.Text
interface org.dom4j.DocumentType
interface org.dom4j.Entity
interface org.dom4j.ProcessingInstruction
一目了然,很多事情都清楚了。大部分都是由Node繼承來(lái)的。知道這些關(guān)系,將來(lái)寫(xiě)程序就不會(huì)出現(xiàn)ClassCastException了。
下面給出一些例子(部分摘自DOM4J自帶的文檔),簡(jiǎn)單說(shuō)一下如何使用。
1.????????????? 讀取并解析XML文檔:
讀寫(xiě)XML文檔主要依賴(lài)于org.dom4j.io包,其中提供DOMReader和SAXReader兩類(lèi)不同方式,而調(diào)用方式是一樣的。這就是依靠接口的好處。
?
??? // 從文件讀取XML,輸入文件名,返回XML文檔
??? public Document read(String fileName) throws MalformedURLException, DocumentException {
?????? SAXReader reader = new SAXReader();
?????? Document document = reader.read(new File(fileName));
?????? return document;
??? }
?
其中,reader的read方法是重載的,可以從InputStream, File, Url等多種不同的源來(lái)讀取。得到的Document對(duì)象就帶表了整個(gè)XML。
根據(jù)本人自己的經(jīng)驗(yàn),讀取的字符編碼是按照XML文件頭定義的編碼來(lái)轉(zhuǎn)換。如果遇到亂碼問(wèn)題,注意要把各處的編碼名稱(chēng)保持一致即可。
2.??? 取得Root節(jié)點(diǎn)
讀取后的第二步,就是得到Root節(jié)點(diǎn)。熟悉XML的人都知道,一切XML分析都是從Root元素開(kāi)始的。
?
? public Element getRootElement(Document doc){
?????? return doc.getRootElement();
??? }
?
3.??? 遍歷XML樹(shù)
DOM4J提供至少3種遍歷節(jié)點(diǎn)的方法:
1) 枚舉(Iterator)
?
??? // 枚舉所有子節(jié)點(diǎn)
??? for ( Iterator i = root.elementIterator(); i.hasNext(); ) {
?????? Element element = (Element) i.next();
?????? // do something
??? }
??? // 枚舉名稱(chēng)為foo的節(jié)點(diǎn)
??? for ( Iterator i = root.elementIterator(foo); i.hasNext();) {
?????? Element foo = (Element) i.next();
?????? // do something
??? }
??? // 枚舉屬性
??? for ( Iterator i = root.attributeIterator(); i.hasNext(); ) {
?????? Attribute attribute = (Attribute) i.next();
?????? // do something
??? }
2)遞歸
遞歸也可以采用Iterator作為枚舉手段,但文檔中提供了另外的做法
?
??? public void treeWalk() {
?????? treeWalk(getRootElement());
??? }
??? public void treeWalk(Element element) {
?????? for (int i = 0, size = element.nodeCount(); i < size; i++)???? {
?????????? Node node = element.node(i);
?????????? if (node instanceof Element) {
????????????? treeWalk((Element) node);
?????????? } else { // do something....
?????????? }
?????? }
}
?
3) Visitor模式
最令人興奮的是DOM4J對(duì)Visitor的支持,這樣可以大大縮減代碼量,并且清楚易懂。了解設(shè)計(jì)模式的人都知道,Visitor是GOF設(shè)計(jì)模式之一。其主要原理就是兩種類(lèi)互相保有對(duì)方的引用,并且一種作為Visitor去訪(fǎng)問(wèn)許多Visitable。我們來(lái)看DOM4J中的Visitor模式(快速文檔中沒(méi)有提供)
只需要自定一個(gè)類(lèi)實(shí)現(xiàn)Visitor接口即可。
?
?????? public class MyVisitor extends VisitorSupport {
?????????? public void visit(Element element){
?????????????? System.out.println(element.getName());
?????????? }
?????????? public void visit(Attribute attr){
?????????????? System.out.println(attr.getName());
?????????? }
??????? }
?
??????? 調(diào)用:? root.accept(new MyVisitor())
??? Visitor接口提供多種Visit()的重載,根據(jù)XML不同的對(duì)象,將采用不同的方式來(lái)訪(fǎng)問(wèn)。上面是給出的Element和Attribute的簡(jiǎn)單實(shí)現(xiàn),一般比較常用的就是這兩個(gè)。VisitorSupport是DOM4J提供的默認(rèn)適配器,Visitor接口的Default Adapter模式,這個(gè)模式給出了各種visit(*)的空實(shí)現(xiàn),以便簡(jiǎn)化代碼。
??? 注意,這個(gè)Visitor是自動(dòng)遍歷所有子節(jié)點(diǎn)的。如果是root.accept(MyVisitor),將遍歷子節(jié)點(diǎn)。我第一次用的時(shí)候,認(rèn)為是需要自己遍歷,便在遞歸中調(diào)用Visitor,結(jié)果可想而知。
4. XPath支持
??? DOM4J對(duì)XPath有良好的支持,如訪(fǎng)問(wèn)一個(gè)節(jié)點(diǎn),可直接用XPath選擇。
?
?? public void bar(Document document) {
??????? List list = document.selectNodes( //foo/bar );
??????? Node node = document.selectSingleNode(//foo/bar/author);
??????? String name = node.valueOf( @name );
???? }
?
??? 例如,如果你想查找XHTML文檔中所有的超鏈接,下面的代碼可以實(shí)現(xiàn):
?
??? public void findLinks(Document document) throws DocumentException {
??????? List list = document.selectNodes( //a/@href );
??????? for (Iterator iter = list.iterator(); iter.hasNext(); ) {
??????????? Attribute attribute = (Attribute) iter.next();
??????????? String url = attribute.getValue();
??????? }
???? }
?
5. 字符串與XML的轉(zhuǎn)換
有時(shí)候經(jīng)常要用到字符串轉(zhuǎn)換為XML或反之,
?
??? // XML轉(zhuǎn)字符串
Document document = ...;
??? String text = document.asXML();
// 字符串轉(zhuǎn)XML
??? String text = <person> <name>James</name> </person>;
??? Document document = DocumentHelper.parseText(text);
?
6 用XSLT轉(zhuǎn)換XML
?
?? public Document styleDocument(
?????? Document document,
?????? String stylesheet
??? ) throws Exception {
??? // load the transformer using JAXP
??? TransformerFactory factory = TransformerFactory.newInstance();
??? Transformer transformer = factory.newTransformer(
?????? new StreamSource( stylesheet )
??? );
??? // now lets style the given document
??? DocumentSource source = new DocumentSource( document );
??? DocumentResult result = new DocumentResult();
??? transformer.transform( source, result );
??? // return the transformed document
??? Document transformedDoc = result.getDocument();
??? return transformedDoc;
}
?
7. 創(chuàng)建XML
? 一般創(chuàng)建XML是寫(xiě)文件前的工作,這就像StringBuffer一樣容易。
?
??? public Document createDocument() {
?????? Document document = DocumentHelper.createDocument();
?????? Element root = document.addElement(root);
?????? Element author1 =
?????????? root
????????????? .addElement(author)
????????????? .addAttribute(name, James)
????????????? .addAttribute(location, UK)
????????????? .addText(James Strachan);
?????? Element author2 =
?????????? root
????????????? .addElement(author)
????????????? .addAttribute(name, Bob)
????????????? .addAttribute(location, US)
????????????? .addText(Bob McWhirter);
?????? return document;
??? }
?
8. 文件輸出
??? 一個(gè)簡(jiǎn)單的輸出方法是將一個(gè)Document或任何的Node通過(guò)write方法輸出
?
??? FileWriter out = new FileWriter( foo.xml );
??? document.write(out);
?
? 如果你想改變輸出的格式,比如美化輸出或縮減格式,可以用XMLWriter類(lèi)
?
??? public void write(Document document) throws IOException {
?????? // 指定文件
?????? XMLWriter writer = new XMLWriter(
?????????? new FileWriter( output.xml )
?????? );
?????? writer.write( document );
?????? writer.close();
?????? // 美化格式
?????? OutputFormat format = OutputFormat.createPrettyPrint();
?????? writer = new XMLWriter( System.out, format );
?????? writer.write( document );
?????? // 縮減格式
?????? format = OutputFormat.createCompactFormat();
?????? writer = new XMLWriter( System.out, format );
?????? writer.write( document );
??? }
?
如何,DOM4J夠簡(jiǎn)單吧,當(dāng)然,還有一些復(fù)雜的應(yīng)用沒(méi)有提到,如ElementHandler等。如果你動(dòng)心了,那就一起來(lái)用DOM4J.
DOM4J官方網(wǎng)站:(我老連不上)
http://www.dom4j.org/
DOM4J下載(SourceForge),最新版本為1.4
http://sourceforge.net/projects/dom4j
用Dom4j解析XML及中文問(wèn)題
發(fā)表于 2004年9月27日 20:21
本文主要討論了用dom4j解析XML的基礎(chǔ)問(wèn)題,包括建立XML文檔,添加、修改、刪除節(jié)點(diǎn),以及格式化(美化)輸出和中文問(wèn)題。可作為dom4j的入門(mén)資料。
轉(zhuǎn)載自:http://jalorsoft.com/holen/
作者:陳光(holen@263.net)
時(shí)間:2004-09-11
?
本文主要討論了用dom4j解析XML的基礎(chǔ)問(wèn)題,包括建立XML文檔,添加、修改、刪除節(jié)點(diǎn),以及格式化(美化)輸出和中文問(wèn)題。可作為dom4j的入門(mén)資料。
?
1. 下載與安裝
?
dom4j是sourceforge.net上的一個(gè)開(kāi)源項(xiàng)目,主要用于對(duì)XML的解析。從2001年7月發(fā)布第一版以來(lái),已陸續(xù)推出多個(gè)版本,目前最高版本為1.5。
dom4j專(zhuān)門(mén)針對(duì)Java開(kāi)發(fā),使用起來(lái)非常簡(jiǎn)單、直觀,在Java界,dom4j正迅速普及。
?
可以到http://sourceforge.net/projects/dom4j下載其最新版。
?
dom4j1.5的完整版大約13M,是一個(gè)名為dom4j-1.5.zip的壓縮包,解壓后有一個(gè)dom4j-1.5.jar文件,這就是應(yīng)用時(shí)需要引入的類(lèi)包,另外還有一個(gè)jaxen-1.1-beta-4.jar文件,一般也需要引入,否則執(zhí)行時(shí)可能拋java.lang.NoClassDefFoundError: org/jaxen/JaxenException異常,其他的包可以選擇用之。
?
2. 示例XML文檔(holen.xml)
?
為了述說(shuō)方便,先看一個(gè)XML文檔,之后的操作均以此文檔為基礎(chǔ)。
?
holen.xml
<?xml version="1.0" encoding="UTF-8"?>
<books>
??? <!--This is a test for dom4j, holen, 2004.9.11-->
??? <book show="yes">
?????? <title>Dom4j Tutorials</title>
??? </book>
??? <book show="yes">
?????? <title>Lucene Studing</title>
??? </book>
??? <book show="no">
?????? <title>Lucene in Action</title>
??? </book>
??? <owner>O'Reilly</owner>
</books>
?
這是一個(gè)很簡(jiǎn)單的XML文檔,場(chǎng)景是一個(gè)網(wǎng)上書(shū)店,有很多書(shū),每本書(shū)有兩個(gè)屬性,一個(gè)是書(shū)名[title],一個(gè)為是否展示[show],最后還有一項(xiàng)是這些書(shū)的擁有者[owner]信息。
?
3. 建立一個(gè)XML文檔
?
?
??? /**
???? * 建立一個(gè)XML文檔,文檔名由輸入屬性決定
???? * @param filename 需建立的文件名
???? * @return 返回操作結(jié)果, 0表失敗, 1表成功
???? */
??? public int createXMLFile(String filename){
?????? /** 返回操作結(jié)果, 0表失敗, 1表成功 */
?????? int returnValue = 0;
?????? /** 建立document對(duì)象 */
?????? Document document = DocumentHelper.createDocument();
?????? /** 建立XML文檔的根books */
?????? Element booksElement = document.addElement("books");
?????? /** 加入一行注釋 */
?????? booksElement.addComment("This is a test for dom4j, holen, 2004.9.11");
?????? /** 加入第一個(gè)book節(jié)點(diǎn) */
?????? Element bookElement = booksElement.addElement("book");
?????? /** 加入show屬性?xún)?nèi)容 */
?????? bookElement.addAttribute("show","yes");
?????? /** 加入title節(jié)點(diǎn) */
?????? Element titleElement = bookElement.addElement("title");
?????? /** 為title設(shè)置內(nèi)容 */
?????? titleElement.setText("Dom4j Tutorials");
??????
?????? /** 類(lèi)似的完成后兩個(gè)book */
?????? bookElement = booksElement.addElement("book");
?????? bookElement.addAttribute("show","yes");
?????? titleElement = bookElement.addElement("title");
?????? titleElement.setText("Lucene Studing");
?????? bookElement = booksElement.addElement("book");
?????? bookElement.addAttribute("show","no");
?????? titleElement = bookElement.addElement("title");
?????? titleElement.setText("Lucene in Action");
??????
?????? /** 加入owner節(jié)點(diǎn) */
?????? Element ownerElement = booksElement.addElement("owner");
?????? ownerElement.setText("O'Reilly");
??????
?????? try{
?????????? /** 將document中的內(nèi)容寫(xiě)入文件中 */
?????????? XMLWriter writer = new XMLWriter(new FileWriter(new File(filename)));
?????????? writer.write(document);
?????????? writer.close();
?????????? /** 執(zhí)行成功,需返回1 */
?????????? returnValue = 1;
?????? }catch(Exception ex){
?????????? ex.printStackTrace();
?????? }
?????????????
?????? return returnValue;
??? }
?
說(shuō)明:
Document document = DocumentHelper.createDocument();
通過(guò)這句定義一個(gè)XML文檔對(duì)象。
?
Element booksElement = document.addElement("books");
通過(guò)這句定義一個(gè)XML元素,這里添加的是根節(jié)點(diǎn)。
Element有幾個(gè)重要的方法:
l???????? addComment:添加注釋
l???????? addAttribute:添加屬性
l???????? addElement:添加子元素
?
最后通過(guò)XMLWriter生成物理文件,默認(rèn)生成的XML文件排版格式比較亂,可以通過(guò)OutputFormat類(lèi)的createCompactFormat()方法或createPrettyPrint()方法格式化輸出,默認(rèn)采用createCompactFormat()方法,顯示比較緊湊,這點(diǎn)將在后面詳細(xì)談到。
?
生成后的holen.xml文件內(nèi)容如下:
?
?
<?xml version="1.0" encoding="UTF-8"?>
<books><!--This is a test for dom4j, holen, 2004.9.11--><book show="yes"><title>Dom4j Tutorials</title></book><book show="yes"><title>Lucene Studing</title></book><book show="no"><title>Lucene in Action</title></book><owner>O'Reilly</owner></books>
?
4. 修改XML文檔
?
有三項(xiàng)修改任務(wù),依次為:
l???????? 如果book節(jié)點(diǎn)中show屬性的內(nèi)容為yes,則修改成no
l???????? 把owner項(xiàng)內(nèi)容改為T(mén)shinghua,并添加date節(jié)點(diǎn)
l???????? 若title內(nèi)容為Dom4j Tutorials,則刪除該節(jié)點(diǎn)
?
?
??? /**
???? * 修改XML文件中內(nèi)容,并另存為一個(gè)新文件
???? * 重點(diǎn)掌握dom4j中如何添加節(jié)點(diǎn),修改節(jié)點(diǎn),刪除節(jié)點(diǎn)
???? * @param filename 修改對(duì)象文件
???? * @param newfilename 修改后另存為該文件
???? * @return 返回操作結(jié)果, 0表失敗, 1表成功
???? */
??? public int ModiXMLFile(String filename,String newfilename){
?????? int returnValue = 0;
?????? try{
?????????? SAXReader saxReader = new SAXReader();
?????????? Document document = saxReader.read(new File(filename));
?????????? /** 修改內(nèi)容之一: 如果book節(jié)點(diǎn)中show屬性的內(nèi)容為yes,則修改成no */
?????????? /** 先用xpath查找對(duì)象 */
?????????? List list = document.selectNodes("/books/book/@show" );
?????????? Iterator iter = list.iterator();
?????????? while(iter.hasNext()){
????????????? Attribute attribute = (Attribute)iter.next();
????????????? if(attribute.getValue().equals("yes")){
????????????????? attribute.setValue("no");
????????????? }??
?????????? }
??????????
?????????? /**
??????????? * 修改內(nèi)容之二: 把owner項(xiàng)內(nèi)容改為T(mén)shinghua
??????????? * 并在owner節(jié)點(diǎn)中加入date節(jié)點(diǎn),date節(jié)點(diǎn)的內(nèi)容為2004-09-11,還為date節(jié)點(diǎn)添加一個(gè)屬性type
??????????? */
?????????? list = document.selectNodes("/books/owner" );
?????????? iter = list.iterator();
?????????? if(iter.hasNext()){
????????????? Element ownerElement = (Element)iter.next();
????????????? ownerElement.setText("Tshinghua");
????????????? Element dateElement = ownerElement.addElement("date");
????????????? dateElement.setText("2004-09-11");
????????????? dateElement.addAttribute("type","Gregorian calendar");
?????????? }
??????????
?????????? /** 修改內(nèi)容之三: 若title內(nèi)容為Dom4j Tutorials,則刪除該節(jié)點(diǎn) */
?????????? list = document.selectNodes("/books/book");
?????????? iter = list.iterator();
?????????? while(iter.hasNext()){
????????????? Element bookElement = (Element)iter.next();
????????????? Iterator iterator = bookElement.elementIterator("title");
????????????? while(iterator.hasNext()){
????????????????? Element titleElement=(Element)iterator.next();
????????????????? if(titleElement.getText().equals("Dom4j Tutorials")){
???????????????????? bookElement.remove(titleElement);
????????????????? }
????????????? }
?????????? }?????????
??????????
?????????? try{
????????????? /** 將document中的內(nèi)容寫(xiě)入文件中 */
????????????? XMLWriter writer = new XMLWriter(new FileWriter(new File(newfilename)));
????????????? writer.write(document);
????????????? writer.close();
????????????? /** 執(zhí)行成功,需返回1 */
????????????? returnValue = 1;
?????????? }catch(Exception ex){
????????????? ex.printStackTrace();
?????????? }
??????????
?????? }catch(Exception ex){
?????????? ex.printStackTrace();
?????? }
?????? return returnValue;
??? }
???
?
說(shuō)明:
List list = document.selectNodes("/books/book/@show" );
list = document.selectNodes("/books/book");
上述代碼通過(guò)xpath查找到相應(yīng)內(nèi)容。
?
通過(guò)setValue()、setText()修改節(jié)點(diǎn)內(nèi)容。
?
通過(guò)remove()刪除節(jié)點(diǎn)或?qū)傩浴?/p>
?
5. 格式化輸出和指定編碼
?
默認(rèn)的輸出方式為緊湊方式,默認(rèn)編碼為UTF-8,但對(duì)于我們的應(yīng)用而言,一般都要用到中文,并且希望顯示時(shí)按自動(dòng)縮進(jìn)的方式的顯示,這就需用到OutputFormat類(lèi)。
?
?
???
??? /**
???? * 格式化XML文檔,并解決中文問(wèn)題
???? * @param filename
???? * @return
???? */
??? public int formatXMLFile(String filename){
?????? int returnValue = 0;
?????? try{
?????????? SAXReader saxReader = new SAXReader();
?????????? Document document = saxReader.read(new File(filename));
?????????? XMLWriter writer = null;
?????????? /** 格式化輸出,類(lèi)型IE瀏覽一樣 */
?????????? OutputFormat format = OutputFormat.createPrettyPrint();
?????????? /** 指定XML編碼 */
?????????? format.setEncoding("GBK");
?????????? writer= new XMLWriter(new FileWriter(new File(filename)),format);
?????????? writer.write(document);
?????????? writer.close();?????
?????????? /** 執(zhí)行成功,需返回1 */
?????????? returnValue = 1;????
?????? }catch(Exception ex){
?????????? ex.printStackTrace();
?????? }
?????? return returnValue;
??? }
?
說(shuō)明:
?
OutputFormat format = OutputFormat.createPrettyPrint();
這句指定了格式化的方式為縮進(jìn)式,則非緊湊式。
?
format.setEncoding("GBK");
指定編碼為GBK。
?
XMLWriter writer = new XMLWriter(new FileWriter(new File(filename)),format);
這與前面兩個(gè)方法相比,多加了一個(gè)OutputFormat對(duì)象,用于指定顯示和編碼方式。
?
6. 完整的類(lèi)代碼
?
前面提出的方法都是零散的,下面給出完整類(lèi)代碼。
?
Dom4jDemo.java
package com.holen.dom4j;
?
import java.io.File;
import java.io.FileWriter;
import java.util.Iterator;
import java.util.List;
?
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
?
/**
?* @author Holen Chen
?*/
public class Dom4jDemo {
???
??? public Dom4jDemo() {
??? }
?
??? public int createXMLFile(String filename){…}
??? public int ModiXMLFile(String filename,String newfilename){…}
??? public int formatXMLFile(String filename){…}
?
??? public static void main(String[] args) {
?????? Dom4jDemo temp = new Dom4jDemo();
?????? System.out.println(temp.createXMLFile("d://holen.xml"));??????? System.out.println(temp.ModiXMLFile("d://holen.xml","d://holen2.xml"));
?????? System.out.println(temp.formatXMLFile("d://holen2.xml"));
??? }
}
?
說(shuō)明:
main()方法中依次調(diào)用三個(gè)方法,第一個(gè)方法用于生成holen.xml,第二個(gè)方法用于修改holen.xml,并且修改后的內(nèi)容另存為holen2.xml,第三個(gè)方法將holen2.xml格式化縮進(jìn)式輸出,并指定編碼方式為GBK。
一個(gè)應(yīng)用Dom4j的例子 ?
[ 2005-4-21 ]
?
Created with Colorer-take5 Library. Type 'net.sf.colorer.FileType@777255'
?
? 0: /*
? 1:? * Created on 2005-4-19
? 2:? *
? 3:? * Copyright (c) 2005 Julysea
? 4:? * Window - Preferences - Java - Code Style - Code Templates
? 5:? */
? 6:
? 7: /*應(yīng)用此log4j的log4j.properties配置文件
? 8:? *
? 9:? *#######################################################################?????
?10:? *# Categories and levels?????????????????????????????????????????????????????
?11:? *#######################################################################?????
?12:? *????????????????????????????????????????????????????????????????????????????
?13:? *log4j.rootCategory=DEBUG, FileApp, ConApp???????????????????????????????????
?14:? *log4j.category.de.jayefem=DEBUG, FileApp, ConApp????????????????????????????
?15:? *????????????????????????????????????????????????????????????????????????????
?16:? *#######################################################################?????
?17:? *# Appenders?????????????????????????????????????????????????????????????????
?18:? *#######################################################################?????
?19:? *????????????????????????????????????????????????????????????????????????????
?20:? *# ConApp is set to be a ConsoleAppender.????????????????????????????????????
?21:? *log4j.appender.ConApp=org.apache.log4j.ConsoleAppender???
?22:? *log4j.appender.ConApp.Target=System.out
?23:? *log4j.appender.ConApp.layout=org.apache.log4j.PatternLayout
?24:? *log4j.appender.ConApp.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n??
?25:? *????????????????????????????????????????????????????????????????????????????
?26:? *# FileApp???????????????????????????????????????????????????????????????????
?27:? *log4j.appender.FileApp=org.apache.log4j.RollingFileAppender?????????????????
?28:? *log4j.appender.FileApp.File=./log4e.log
?29:? *log4j.appender.FileApp.MaxFileSize=500KB????????????????????????????????????
?30:? *# Keep one backup file??????????????????????????????????????????????????????
?31:? *log4j.appender.FileApp.MaxBackupIndex=1?????????????????????????????????????
?32:? *log4j.appender.FileApp.layout=org.apache.log4j.PatternLayout????????????????
?33:? *log4j.appender.FileApp.layout.ConversionPattern=%d [%t] %-5p %c - %m%n?
?34:? */
?35:
?36:
?37: /*應(yīng)用此XML文件做測(cè)試
?38:? *
?39:? *<EW cmd="login" mod="Login" version="6.0">
?40:? *<Source uns="" type="user"/>
?41:? *<Username>zhangzhiyun@hp</Username>
?42:? *<Password>111111</Password>
?43:? *<Version>6.01.06.00</Version>
?44:? *</EW>
?45:? */
?46: package xml;
?47:
?48: import java.io.BufferedReader;
?49: import java.io.BufferedWriter;
?50: import java.io.File;
?51: import java.io.FileReader;
?52: import java.io.FileWriter;
?53: import java.io.IOException;
?54:
?55: import org.apache.log4j.Logger;
?56: import org.dom4j.Attribute;
?57: import org.dom4j.DocumentException;
?58: import org.dom4j.DocumentHelper;
?59: import org.dom4j.Element;
?60:
?61: /**
?62:? * @author julysea
?63:? *
?64:? * 一個(gè)用Dom4j解析xml的例子
?65:? *
?66:? */
?67: public class Dom4jTest {
?68:
?69:???? private static final Logger logger = Logger.getLogger(Dom4jTest.class);
?70:
?71:???? public static void main(String[] args) throws IOException,
?72:???????????? DocumentException {
?73:???????? BufferedReader reader=new BufferedReader(new FileReader("ew.xml"));
?74:???????? String tempStr;
?75:???????? String ewXml="";
?76:???????? while((tempStr=reader.readLine())!=null) {
?77:???????????? ewXml=ewXml+tempStr;
?78:???????????? logger.debug(tempStr);
?79:???????? }
?80:???????? Element root = null;
?81:????????
?82:???????? root = DocumentHelper.parseText(ewXml).getRootElement();
?83:???????? Attribute rootCmd=root.attribute("cmd");
?84:???????? Attribute rootVersion=root.attribute("version");
?85:???????? logger.debug("rootNmae = "+root.getName());
?86:???????? logger.debug("EW'cmd = "+rootCmd.getValue());
?87:???????? logger.debug("EW'version = "+rootVersion.getValue());
?88:????????
?89:???????? Element usrName=root.element("Username");
?90:???????? logger.debug("EW.Username value = "+usrName.getTextTrim());
?91:????????
?92:???????? Element source=root.element("Source");
?93:???????? Attribute sourceUns=source.attribute("uns");
?94:???????? logger.debug("EW.Source'uns"+sourceUns.getValue());
?95:???????? Attribute sourceType=source.attribute("type");
?96:???????? logger.debug("EW.Source'type = "+sourceType.getValue());
?97:????????
?98:????????
?99:???????? //創(chuàng)建一個(gè)Xml文件
100:???????? Element user=DocumentHelper.createElement("User");
101:???????? user.addAttribute("type", "user");
102:???????? user.addElement("name").addAttribute("type", "PinYin").setText("Julysea");
103:???????? user.addElement("age").setText("29");
104:???????? String oneXml=user.asXML();
105:????????
106:???????? BufferedWriter out=new BufferedWriter(new FileWriter("oneXml.xml"));
107:???????? out.write(oneXml);
108:???????? out.close();
109:???? }
110: }
?
Dom4j編碼問(wèn)題徹底解決
?
?
這幾天開(kāi)始學(xué)習(xí)dom4j,在網(wǎng)上找了篇文章就開(kāi)干了,上手非常的快,但是發(fā)現(xiàn)了個(gè)問(wèn)題就是無(wú)法以UTF-8保存xml文件,保存后再次讀出的時(shí)候會(huì)報(bào)“Invalid byte 2 of 2-byte UTF-8 sequence.”這樣一個(gè)錯(cuò)誤,檢查發(fā)現(xiàn)由dom4j生成的這個(gè)文件,在使用可正確處理XML編碼的任何的編輯器中中文成亂碼,從記事本查看并不會(huì)出現(xiàn)亂碼會(huì)正確顯示中文。讓我很是頭痛。試著使用GBK、gb2312編碼來(lái)生成的xml文件卻可以正常的被解析。因此懷疑的dom4j沒(méi)有對(duì)utf-8編碼進(jìn)行處理。便開(kāi)始查看dom4j的原代碼。終于發(fā)現(xiàn)的問(wèn)題所在,是自己程序的問(wèn)題。
?? 在dom4j的范例和網(wǎng)上流行的《DOM4J 使用簡(jiǎn)介》這篇教程中新建一個(gè)xml文檔的代碼都類(lèi)似如下
??? public void createXML(String fileName) {
??????? document.nbspdoc = org.dom4j.document.elper.createdocument.);
??????? Element root = doc.addElement("book");
??????? root.addAttribute("name", "我的圖書(shū)");
?
??????? Element childTmp;
??????? childTmp = root.addElement("price");
??????? childTmp.setText("21.22");
?
??????? Element writer = root.addElement("author");
??????? writer.setText("李四");
??????? writer.addAttribute("ID", "001");
?
??????? try {
??????????? org.dom4j.io.XMLWriter xmlWriter = new org.dom4j.io.XMLWriter(
??????????????????? new FileWriter(fileName));
??????????? xmlWriter.write(doc);
??????????? xmlWriter.close();
??????? }
??????? catch (Exception e) {
??????????? System.out.println(e);
??????? }
??? }
?? 在上面的代碼中輸出使用的是FileWriter對(duì)象進(jìn)行文件的輸出。這就是不能正確進(jìn)行文件編碼的原因所在,java中由Writer類(lèi)繼承下來(lái)的子類(lèi)沒(méi)有提供編碼格式處理,所以dom4j也就無(wú)法對(duì)輸出的文件進(jìn)行正確的格式處理。這時(shí)候所保存的文件會(huì)以系統(tǒng)的默認(rèn)編碼對(duì)文件進(jìn)行保存,在中文版的window下java的默認(rèn)的編碼為GBK,也就是所雖然我們標(biāo)識(shí)了要將xml保存為utf-8格式但實(shí)際上文件是以GBK格式來(lái)保存的,所以這也就是為什么能夠我們使用GBK、GB2312編碼來(lái)生成xml文件能正確的被解析,而以UTF-8格式生成的文件不能被xml解析器所解析的原因。
?? 好了現(xiàn)在我們找到了原因所在了,我們來(lái)找解決辦法吧。首先我們看看dom4j是如何實(shí)現(xiàn)編碼處理的
?? public XMLWriter(OutputStream out) throws UnsupportedEncodingException {
??????? //System.out.println("In OutputStream");
??????? this.format = DEFAULT_FORMAT;
??????? this.writer = createWriter(out, format.getEncoding());
??????? this.autoFlush = true;
?????? namespaceStack.push(Namespace.NO_NAMESPACE);
??? }
?
??? public XMLWriter(OutputStream out, OutputFormat format) throws UnsupportedEncodingException {
??????? //System.out.println("In OutputStream,OutputFormat");
??????? this.format = format;
??????? this.writer = createWriter(out, format.getEncoding());
??????? this.autoFlush = true;
?????? namespaceStack.push(Namespace.NO_NAMESPACE);
??? }
??? /**
???? * Get an OutputStreamWriter, use preferred encoding.
???? */
??? protected Writer createWriter(OutputStream outStream, String encoding) throws UnsupportedEncodingException {
??????? return new BufferedWriter(
??????????? new OutputStreamWriter( outStream, encoding )
??????? );
??? }
?? 由上面的代碼我們可以看出dom4j對(duì)編碼并沒(méi)有進(jìn)行什么很復(fù)雜的處理,完全通過(guò)java本身的功能來(lái)完成。所以我們?cè)谑褂胐om4j的來(lái)生成我們的XML文件時(shí)不應(yīng)該直接為在構(gòu)建XMLWriter時(shí),不應(yīng)該直接為其賦一個(gè)Writer對(duì)象,而應(yīng)該通過(guò)一個(gè)OutputStream的子類(lèi)對(duì)象來(lái)構(gòu)建。也就是說(shuō)在我們上面的代碼中,不應(yīng)該用FileWriter對(duì)象來(lái)構(gòu)建xml文檔,而應(yīng)該使用FileOutputStream對(duì)象來(lái)構(gòu)建所以將代碼修改入下:
??? public void createXML(String fileName) {
??????? document.nbspdoc = org.dom4j.document.elper.createdocument.);
??????? Element root = doc.addElement("book");
??????? root.addAttribute("name", "我的圖書(shū)");
?
??????? Element childTmp;
??????? childTmp = root.addElement("price");
??????? childTmp.setText("21.22");
?
??????? Element writer = root.addElement("author");
??????? writer.setText("李四");
??????? writer.addAttribute("ID", "001");
?
??????? try {
??????????? //注意這里的修改
??????????? org.dom4j.io.XMLWriter xmlWriter = new org.dom4j.io.XMLWriter(
??????????????????? new FileOutputStream(fileName));
??????????? xmlWriter.write(doc);
??????????? xmlWriter.close();
??????? }
??????? catch (Exception e) {
??????????? System.out.println(e);
??????? }
??? }
?
?? 至此DOM4J的問(wèn)題編碼問(wèn)題算是告一段落,希望對(duì)此文章對(duì)其他朋友有用。
Dom4j的基本使用
下載dom4j后,在其文檔中就用詳細(xì)的使用說(shuō)明,我又將其封裝了一下:
package org.tju.msnrl.butil;
import java.io.*;
import java.util.*;
import org.dom4j.*;
import org.dom4j.io.XMLWriter;
import org.dom4j.io.SAXReader;
/**
?* Dom4j封裝類(lèi)
?* <p>Title: 天津大學(xué)博士后流動(dòng)站</p>
?* <p>Description: 天津大學(xué)人事處制作維護(hù)</p>
?* <p>Copyright: Copyright (c) 2005</p>
?* <p>Company: 天津大學(xué)軟件學(xué)院.NET實(shí)驗(yàn)室(MSNRL)</p>
?* @author Jonathan Q. Bo
?* @version 1.0
?*/
public class BDom4j {
? /**XML文件路徑*/
? private String XMLPath = null;
? /**XML文檔*/
? private Document document = null;
? public BDom4j() {
? }
? /**
?? * 初始化xml文件
?? * @param XMLPath 文件路徑
?? */
? public BDom4j(String XMLPath){
??? this.XMLPath = XMLPath;
? }
? /**
?? * 打開(kāi)文檔
?? */
? public void openXML(){
??? try{
????? SAXReader reader = new SAXReader();
????? this.document = reader.read(this.XMLPath);
????? System.out.println("openXML() successful ...");
??? }catch(Exception e){
????? System.out.println("openXML() Exception:" + e.getMessage());
??? }
? }
?
? /**
?? * 創(chuàng)建文檔
?? * @param rootName 根節(jié)點(diǎn)名稱(chēng)
?? */
? public void createXML(String rootName){
??? try{
????? this.document = DocumentHelper.createDocument();
????? Element root = document.addElement(rootName);
????? System.out.println("createXML() successful...");
??? }catch(Exception e){
????? System.out.println("createXML() Exception:" + e.getMessage());
??? }
? }
? /**
?? * 添加根節(jié)點(diǎn)的child
?? * @param nodeName 節(jié)點(diǎn)名
?? * @param nodeValue 節(jié)點(diǎn)值
?? */
? public void addNodeFromRoot(String nodeName, String nodeValue){
??? Element root = this.document.getRootElement();
??? Element level1 = root.addElement(nodeName);
??? level1.addText(nodeValue);
? }
? /**
?? * 打開(kāi)文檔
?? * @param filePath 文檔路徑
?? */
? public void openXML(String filePath){
??? try{
????? SAXReader saxReader = new SAXReader();
????? this.document = saxReader.read(filePath);
????? System.out.println("openXML(String filePath) successful ...");
??? }catch(Exception e){
????? System.out.println("openXML() Exception:" + e.getMessage());
??? }
? }
? /**
?? * 保存文檔
?? */
? public void saveXML(){
??? try{
????? XMLWriter output = new XMLWriter(new FileWriter(new File(this.XMLPath)));
????? output.write(document);
????? output.close();
????? System.out.println("saveXML() successful ...");
??? }catch(Exception e1){
????? System.out.println("saveXML() Exception:" + e1.getMessage());
??? }
? }
? /**
?? * 保存文檔
?? * @param toFilePath 保存路徑
?? */
? public void saveXML(String toFilePath) {
??? try {
????? XMLWriter output = new XMLWriter(new FileWriter(new File(toFilePath)));
????? output.write(document);
????? output.close();
??? }
??? catch (Exception e1) {
????? System.out.println("saveXML() Exception:" + e1.getMessage());
??? }
? }
? /**
?? * 獲得某個(gè)節(jié)點(diǎn)的值
?? * @param nodeName 節(jié)點(diǎn)名稱(chēng)
?? */
? public String getElementValue(String nodeName){
??? try {
????? Node node = document.selectSingleNode("http://" + nodeName);
????? return node.getText();
??? }
??? catch (Exception e1) {
????? System.out.println("getElementValue() Exception:" + e1.getMessage());
????? return null;
??? }
? }
? /**
?? * 獲得某個(gè)節(jié)點(diǎn)的子節(jié)點(diǎn)的值
?? * @param nodeName
?? * @param childNodeName
?? * @return
?? */
? public String getElementValue(String nodeName, String childNodeName){
??? try {
????? Node node = this.document.selectSingleNode("http://" + nodeName + "/" + childNodeName);
????? return node.getText();
??? }
??? catch (Exception e1) {
????? System.out.println("getElementValue() Exception:" + e1.getMessage());
????? return null;
??? }
? }
? /**
?? * 設(shè)置一個(gè)節(jié)點(diǎn)的text
?? * @param nodeName 節(jié)點(diǎn)名
?? * @param nodeValue 節(jié)點(diǎn)值
?? */
? public void setElementValue(String nodeName, String nodeValue){
??? try{
????? Node node = this.document.selectSingleNode("http://" + nodeName);
????? node.setText(nodeValue);
??? }catch(Exception e1){
????? System.out.println("setElementValue() Exception:" + e1.getMessage());
??? }
? }
? /**
?? * 設(shè)置一個(gè)節(jié)點(diǎn)值
?? * @param nodeName 父節(jié)點(diǎn)名
?? * @param childNodeName 節(jié)點(diǎn)名
?? * @param nodeValue 節(jié)點(diǎn)值
?? */
? public void setElementValue(String nodeName, String childNodeName,
????????????????????????????? String nodeValue) {
??? try {
????? Node node = this.document.selectSingleNode("http://" + nodeName + "/" + childNodeName);
????? node.setText(nodeValue);
??? }
??? catch (Exception e1) {
????? System.out.println("setElementValue() Exception:" + e1.getMessage());
??? }
? }
}
簡(jiǎn)單封裝后,可以用來(lái)讀寫(xiě)XML文檔,對(duì)網(wǎng)站進(jìn)行配置:如指定頁(yè)面整體風(fēng)格的css文件,在context init 時(shí)讀取存入context中,在頁(yè)面中通過(guò)讀取context中的相應(yīng)屬性來(lái)確定css文件名,完成一項(xiàng)配置,其它的動(dòng)態(tài)配置都類(lèi)似;
public class BListener extends HttpServlet implements ServletContextListener, ServletContextAttributeListener, HttpSessionListener, HttpSessionAttributeListener {
? private static String XML_FILE_PATH = "c:/test.xml";
? //Notification that the web application is ready to process requests
? public void contextInitialized(ServletContextEvent sce) {
??? BDom4j xmlmng = new BDom4j(XML_FILE_PATH);
??? xmlmng.openXML();
??? sce.getServletContext().setAttribute("css",xmlmng.getElementValue("style-sheet"));
??? System.out.println("### context initialized...");
? }
?
|----------------------------------------------------------------------------------------|
版權(quán)聲明 版權(quán)所有 @zhyiwww
引用請(qǐng)注明來(lái)源 http://www.tkk7.com/zhyiwww
|----------------------------------------------------------------------------------------|
posted on 2006-07-11 17:16
zhyiwww 閱讀(1996)
評(píng)論(2) 編輯 收藏 所屬分類(lèi):
j2ee