空間站

          北極心空

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            15 Posts :: 393 Stories :: 160 Comments :: 0 Trackbacks
          Dom4j 使用簡介
          作者:冰云 icecloud(AT)sina.com
          時間:2003.12.15
           
          版權(quán)聲明:
          本文由冰云完成,首發(fā)于CSDN,未經(jīng)許可,不得使用于任何商業(yè)用途。
          文中代碼部分引用自DOM4J文檔。
          歡迎轉(zhuǎn)載,但請保持文章及版權(quán)聲明完整。
          如需聯(lián)絡(luò)請發(fā)郵件:icecloud(AT)sina.com
           
              DOM4J是dom4j.org出品的一個開源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是一個易用的、開源的庫,用于XMLXPathXSLT。它應(yīng)用于Java平臺,采用了Java集合框架并完全支持DOMSAXJAXP
          DOM4J使用起來非常簡單。只要你了解基本的XML-DOM模型,就能使用。然而他自己帶的指南只有短短一頁(html),不過說的到挺全。國內(nèi)的中文資料很少。因而俺寫這個短小的教程方便大家使用,這篇文章僅談及基本的用法,如需深入的使用,請……自己摸索或查找別的資料。
          之前看過IBM developer社區(qū)的文章(參見附錄),提到一些XML解析包的性能比較,其中DOM4J的性能非常出色,在多項測試中名列前茅。(事實上DOM4J的官方文檔中也引用了這個比較)所以這次的項目中我采用了DOM4J作為XML解析工具。
          在國內(nèi)比較流行的是使用JDOM作為解析器,兩者各擅其長,但DOM4J最大的特色是使用大量的接口,這也是它被認(rèn)為比JDOM靈活的主要原因。大師不是說過么,“面向接口編程”。目前使用DOM4J的已經(jīng)越來越多。如果你善于使用JDOM,不妨繼續(xù)用下去,只看看本篇文章作為了解與比較,如果你正要采用一種解析器,不如就用DOM4J吧。
          它的主要接口都在org.dom4j這個包里定義:
          Attribute定義了XML的屬性
          Branch為能夠包含子節(jié)點的節(jié)點如XML元素(Element)和文檔(Docuemnts)定義了一個公共的行為,
          CDATA 定義了XML CDATA 區(qū)域
          CharacterData是一個標(biāo)識借口,標(biāo)識基于字符的節(jié)點。如CDATA,Comment, Text.
          Comment 定義了XML注釋的行為
          定義了XML文檔
          DocumentType 定義XML DOCTYPE聲明
          Element定義XML 元素
          ElementHandler定義了 Element 對象的處理器
          ElementHandler 使用,用于取得當(dāng)前正在處理的路徑層次信息
          Entity定義 XML entity
          Node為所有的dom4j中XML節(jié)點定義了多態(tài)行為
          NodeFilter 定義了在dom4j節(jié)點中產(chǎn)生的一個濾鏡或謂詞的行為(predicate)
          ProcessingInstruction 定義 XML 處理指令.
          Text 定義XML 文本節(jié)點.
          Visitor 用于實現(xiàn)Visitor模式.
          XPath 在分析一個字符串后會提供一個XPath 表達(dá)式
          看名字大致就知道它們的涵義如何了。
          要想弄懂這套接口,關(guān)鍵的是要明白接口的繼承關(guān)系:
          一目了然,很多事情都清楚了。大部分都是由Node繼承來的。知道這些關(guān)系,將來寫程序就不會出現(xiàn)ClassCastException了。
          下面給出一些例子(部分摘自DOM4J自帶的文檔),簡單說一下如何使用。
          1.              讀取并解析XML文檔:
          讀寫XML文檔主要依賴于org.dom4j.io包,其中提供DOMReader和SAXReader兩類不同方式,而調(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等多種不同的源來讀取。得到的Document對象就帶表了整個XML。
          根據(jù)本人自己的經(jīng)驗,讀取的字符編碼是按照XML文件頭定義的編碼來轉(zhuǎn)換。如果遇到亂碼問題,注意要把各處的編碼名稱保持一致即可。
          2.    取得Root節(jié)點
          讀取后的第二步,就是得到Root節(jié)點。熟悉XML的人都知道,一切XML分析都是從Root元素開始的。
           
             public Element getRootElement(Document doc){
                 return doc.getRootElement();
              }
           
          3.    遍歷XML樹
          DOM4J提供至少3種遍歷節(jié)點的方法:
          1) 枚舉(Iterator)
           
              // 枚舉所有子節(jié)點
              for ( Iterator i = root.elementIterator(); i.hasNext(); ) {
                 Element element = (Element) i.next();
                 // do something
              }
              // 枚舉名稱為foo的節(jié)點
              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對Visitor的支持,這樣可以大大縮減代碼量,并且清楚易懂。了解設(shè)計模式的人都知道,Visitor是GOF設(shè)計模式之一。其主要原理就是兩種類互相保有對方的引用,并且一種作為Visitor去訪問許多Visitable。我們來看DOM4J中的Visitor模式(快速文檔中沒有提供)
          只需要自定一個類實現(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不同的對象,將采用不同的方式來訪問。上面是給出的Element和Attribute的簡單實現(xiàn),一般比較常用的就是這兩個。VisitorSupport是DOM4J提供的默認(rèn)適配器,Visitor接口的Default Adapter模式,這個模式給出了各種visit(*)的空實現(xiàn),以便簡化代碼。
              注意,這個Visitor是自動遍歷所有子節(jié)點的。如果是root.accept(MyVisitor),將遍歷子節(jié)點。我第一次用的時候,認(rèn)為是需要自己遍歷,便在遞歸中調(diào)用Visitor,結(jié)果可想而知。
          4. XPath支持
              DOM4J對XPath有良好的支持,如訪問一個節(jié)點,可直接用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文檔中所有的超鏈接,下面的代碼可以實現(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)換
          有時候經(jīng)常要用到字符串轉(zhuǎn)換為XML或反之,
           
              // XML轉(zhuǎn)字符串
            Document document = ...;
              String text = document.asXML();
          // 字符串轉(zhuǎn)XML
              String text = James ;
              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是寫文件前的工作,這就像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. 文件輸出
              一個簡單的輸出方法是將一個Document或任何的Node通過write方法輸出
           
              FileWriter out = new FileWriter( foo.xml );
              document.write(out);
           
            如果你想改變輸出的格式,比如美化輸出或縮減格式,可以用XMLWriter類
           
              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夠簡單吧,當(dāng)然,還有一些復(fù)雜的應(yīng)用沒有提到,如ElementHandler等。如果你動心了,那就一起來用DOM4J.
          DOM4J官方網(wǎng)站:(我老連不上)
          DOM4J下載(SourceForge),最新版本為1.4
          發(fā)表于 2004年9月27日 20:21
          本文主要討論了用dom4j解析XML的基礎(chǔ)問題,包括建立XML文檔,添加、修改、刪除節(jié)點,以及格式化(美化)輸出和中文問題。可作為dom4j的入門資料。
          轉(zhuǎn)載自:http://jalorsoft.com/holen/
          作者:陳光(holen@263.net
          時間:2004-09-11
           
          本文主要討論了用dom4j解析XML的基礎(chǔ)問題,包括建立XML文檔,添加、修改、刪除節(jié)點,以及格式化(美化)輸出和中文問題。可作為dom4j的入門資料。
           
          1 下載與安裝
           
          dom4j是sourceforge.net上的一個開源項目,主要用于對XML的解析。從2001年7月發(fā)布第一版以來,已陸續(xù)推出多個版本,目前最高版本為1.5。
          dom4j專門針對Java開發(fā),使用起來非常簡單、直觀,在Java界,dom4j正迅速普及。
           
          可以到http://sourceforge.net/projects/dom4j下載其最新版。
           
          dom4j1.5的完整版大約13M,是一個名為dom4j-1.5.zip的壓縮包,解壓后有一個dom4j-1.5.jar文件,這就是應(yīng)用時需要引入的類包,另外還有一個jaxen-1.1-beta-4.jar文件,一般也需要引入,否則執(zhí)行時可能拋java.lang.NoClassDefFoundError: org/jaxen/JaxenException異常,其他的包可以選擇用之。
           
          2 示例XML文檔(holen.xml
           
          為了述說方便,先看一個XML文檔,之后的操作均以此文檔為基礎(chǔ)。
           

          holen.xml
          <?xml version="1.0" encoding="UTF-8"?>
              <!--This is a test for dom4j, holen, 2004.9.11-->
             
                
             
             
                
             
             
                
             
              O'Reilly

           
          這是一個很簡單的XML文檔,場景是一個網(wǎng)上書店,有很多書,每本書有兩個屬性,一個是書名[title],一個為是否展示[show],最后還有一項是這些書的擁有者[owner]信息。
           
          3 建立一個XML文檔
           

           
              /**
               * 建立一個XML文檔,文檔名由輸入屬性決定
               * @param filename 需建立的文件名
               * @return 返回操作結(jié)果, 0表失敗, 1表成功
               */
              public int createXMLFile(String filename){
                 /** 返回操作結(jié)果, 0表失敗, 1表成功 */
                 int returnValue = 0;
                 /** 建立document對象 */
                 Document document = DocumentHelper.createDocument();
                 /** 建立XML文檔的根books */
                 Element booksElement = document.addElement("books");
                 /** 加入一行注釋 */
                 booksElement.addComment("This is a test for dom4j, holen, 2004.9.11");
                 /** 加入第一個book節(jié)點 */
                 Element bookElement = booksElement.addElement("book");
                 /** 加入show屬性內(nèi)容 */
                 bookElement.addAttribute("show","yes");
                 /** 加入title節(jié)點 */
                 Element titleElement = bookElement.addElement("title");
                 /** 為title設(shè)置內(nèi)容 */
                 titleElement.setText("Dom4j Tutorials");
                
                 /** 類似的完成后兩個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é)點 */
                 Element ownerElement = booksElement.addElement("owner");
                 ownerElement.setText("O'Reilly");
                
                 try{
                     /** 將document中的內(nèi)容寫入文件中 */
                     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;
              }

           
          說明:
          Document document = DocumentHelper.createDocument();
          通過這句定義一個XML文檔對象。
           
          Element booksElement = document.addElement("books");
          通過這句定義一個XML元素,這里添加的是根節(jié)點。
          Element有幾個重要的方法:
          l         addComment:添加注釋
          l         addAttribute:添加屬性
          l         addElement:添加子元素
           
          最后通過XMLWriter生成物理文件,默認(rèn)生成的XML文件排版格式比較亂,可以通過OutputFormat類的createCompactFormat()方法或createPrettyPrint()方法格式化輸出,默認(rèn)采用createCompactFormat()方法,顯示比較緊湊,這點將在后面詳細(xì)談到。
           
          生成后的holen.xml文件內(nèi)容如下:
           

           
          <?xml version="1.0" encoding="UTF-8"?>
          <!--This is a test for dom4j, holen, 2004.9.11-->O'Reilly

           
          4 修改XML文檔
           
          有三項修改任務(wù),依次為:
          l         如果book節(jié)點中show屬性的內(nèi)容為yes,則修改成no
          l         把owner項內(nèi)容改為Tshinghua,并添加date節(jié)點
          l         若title內(nèi)容為Dom4j Tutorials,則刪除該節(jié)點
           

           
              /**
               * 修改XML文件中內(nèi)容,并另存為一個新文件
               * 重點掌握dom4j中如何添加節(jié)點,修改節(jié)點,刪除節(jié)點
               * @param filename 修改對象文件
               * @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é)點中show屬性的內(nèi)容為yes,則修改成no */
                     /** 先用xpath查找對象 */
                     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項內(nèi)容改為Tshinghua
                      * 并在owner節(jié)點中加入date節(jié)點,date節(jié)點的內(nèi)容為2004-09-11,還為date節(jié)點添加一個屬性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é)點 */
                     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)容寫入文件中 */
                        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;
              }
             

           
          說明:
          List list = document.selectNodes("/books/book/@show" );
          list = document.selectNodes("/books/book");
          上述代碼通過xpath查找到相應(yīng)內(nèi)容。
           
          通過setValue()、setText()修改節(jié)點內(nèi)容。
           
          通過remove()刪除節(jié)點或?qū)傩浴?/div>
           
          5 格式化輸出和指定編碼
           
          默認(rèn)的輸出方式為緊湊方式,默認(rèn)編碼為UTF-8,但對于我們的應(yīng)用而言,一般都要用到中文,并且希望顯示時按自動縮進(jìn)的方式的顯示,這就需用到OutputFormat類。
           

           
             
              /**
               * 格式化XML文檔,并解決中文問題
               * @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;
                     /** 格式化輸出,類型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;
              }

           
          說明:
           
          OutputFormat format = OutputFormat.createPrettyPrint();
          這句指定了格式化的方式為縮進(jìn)式,則非緊湊式。
           
          format.setEncoding("GBK");
          指定編碼為GBK。
           
          XMLWriter writer = new XMLWriter(new FileWriter(new File(filename)),format);
          這與前面兩個方法相比,多加了一個OutputFormat對象,用于指定顯示和編碼方式。
           
          6 完整的類代碼
           
          前面提出的方法都是零散的,下面給出完整類代碼。
           

          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</

          17:43  |   永久鏈接  |   瀏覽 (4666)  |   評論 (2)  |    收藏  |   技術(shù)  |  
          評論    共 2 條 發(fā)表評論
          yangyanninhao     2007-08-13 15:11

          太好了,謝謝!收藏。

          chenlb     2007-09-06 00:09

          如果是UTF-8
          FileWriter 改用 FileOutputStream

          代碼
          1. XMLWriter writer;   
          2.         try {   
          3.             OutputFormat format = OutputFormat.createPrettyPrint();   
          4.             //format.setEncoding("UTF-8");   
          5.             FileOutputStream fos = new FileOutputStream(xmlFile);   
          6.             //writer = new XMLWriter(new FileWriter(xmlFile), format);   
          7.             writer = new XMLWriter(fos, format);   
          8.             writer.write(document);   
          9.             writer.close();   
          10.         } catch (IOException e) {   
          11.             // TODO 自動生成 catch 塊   
          12.             logger.error("修改xml文件失敗!");   
          13.             e.printStackTrace();   
          14.         }   

           

          posted on 2007-10-19 16:40 蘆葦 閱讀(103515) 評論(1)  編輯  收藏 所屬分類: XML

          Feedback

          # re: Dom4j的使用(全而好的文章) 2015-09-08 08:44 謝謝了很有用
          謝謝了我是初學(xué)者 這對我用處太大了  回復(fù)  更多評論
            

          主站蜘蛛池模板: 卓资县| 长岛县| 湘乡市| 佳木斯市| 出国| 得荣县| 嫩江县| 广安市| 鄂州市| 鄂托克前旗| 赣榆县| 兰考县| 岳池县| 湄潭县| 宜君县| 潼关县| 新和县| 尖扎县| 平山县| 都兰县| 应用必备| 凉城县| 高陵县| 津市市| 安溪县| 逊克县| 商洛市| 台前县| 伊金霍洛旗| 正定县| 新邵县| 潞城市| 当阳市| 汉沽区| 金溪县| 古蔺县| 陇西县| 武安市| 通山县| 建水县| 绿春县|