dom4j操作XML

 

dom4j操作XML

dom4j这个包里定义定义的接口:

 

看名字大致就知道它们的涵义如何了。

要想弄懂这套接口,关键的是要明白接口的继承关系:

一目了然,很多事情都清楚了。大部分都是由Node继承来的。知道这些关系,将来写程序就不会出现ClassCastException了。

下面给出一些例子(部分摘自DOM4J自带的文档),简单说一下如何使用。

1.              读取并解析XML文档:

读写XML文档主要依赖于org.dom4j.io包,其中提供DOMReader和SAXReader两类不同方式,而调用方式是一样的。这就是依靠接口的好处。

 

    // 从文件读取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。

根据本人自己的经验,读取的字符编码是按照XML文件头定义的编码来转换。如果遇到乱码问题,注意要把各处的编码名称保持一致即可。

2.    取得Root节点

读取后的第二步,就是得到Root节点。熟悉XML的人都知道,一切XML分析都是从Root元素开始的。

 

   public Element getRootElement(Document doc){

       return doc.getRootElement();

    }

 

3.    遍历XML树

DOM4J提供至少3种遍历节点的方法:

1) 枚举(Iterator)

 

    // 枚举所有子节点

    for ( Iterator i = root.elementIterator(); i.hasNext(); ) {

       Element element = (Element) i.next();

       // do something

    }

    // 枚举名称为foo的节点

    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的支持,这样可以大大缩减代码量,并且清楚易懂。了解设计模式的人都知道,Visitor是GOF设计模式之一。其主要原理就是两种类互相保有对方的引用,并且一种作为Visitor去访问许多Visitable。我们来看DOM4J中的Visitor模式(快速文档中没有提供)

只需要自定一个类实现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());

           }

        }

 

        调用:  root.accept(new MyVisitor())

    Visitor接口提供多种Visit()的重载,根据XML不同的对象,将采用不同的方式来访问。上面是给出的Element和Attribute的简单实现,一般比较常用的就是这两个。VisitorSupport是DOM4J提供的默认适配器,Visitor接口的Default Adapter模式,这个模式给出了各种visit(*)的空实现,以便简化代码。

    注意,这个Visitor是自动遍历所有子节点的。如果是root.accept(MyVisitor),将遍历子节点。我第一次用的时候,认为是需要自己遍历,便在递归中调用Visitor,结果可想而知。

4. XPath支持

    DOM4J对XPath有良好的支持,如访问一个节点,可直接用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文档中所有的超链接,下面的代码可以实现:

 

    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的转换

有时候经常要用到字符串转换为XML或反之,

 

    // XML转字符串

  Document document = ...;

    String text = document.asXML();

// 字符串转XML

    String text = James ;

    Document document = DocumentHelper.parseText(text);

 

6 用XSLT转换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. 创建XML

  一般创建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够简单吧,当然,还有一些复杂的应用没有提到,如ElementHandler等。如果你动心了,那就一起来用DOM4J.

DOM4J官方网站:(我老连不上)

http://www.dom4j.org/

DOM4J下载(SourceForge),最新版本为1.4

http://sourceforge.net/projects/dom4j

用Dom4j解析XML及中文问题

发表于 2004年9月27日 20:21

本文主要讨论了用dom4j解析XML的基础问题,包括建立XML文档,添加、修改、删除节点,以及格式化(美化)输出和中文问题。可作为dom4j的入门资料。

转载自:http://jalorsoft.com/holen/

作者:陈光(holen@263.net

时间:2004-09-11

 

本文主要讨论了用dom4j解析XML的基础问题,包括建立XML文档,添加、修改、删除节点,以及格式化(美化)输出和中文问题。可作为dom4j的入门资料。

 

1. 下载与安装

 

dom4j是sourceforge.net上的一个开源项目,主要用于对XML的解析。从2001年7月发布第一版以来,已陆续推出多个版本,目前最高版本为1.5。

dom4j专门针对Java开发,使用起来非常简单、直观,在Java界,dom4j正迅速普及。

 

可以到http://sourceforge.net/projects/dom4j下载其最新版。

 

dom4j1.5的完整版大约13M,是一个名为dom4j-1.5.zip的压缩包,解压后有一个dom4j-1.5.jar文件,这就是应用时需要引入的类包,另外还有一个jaxen-1.1-beta-4.jar文件,一般也需要引入,否则执行时可能抛java.lang.NoClassDefFoundError: org/jaxen/JaxenException异常,其他的包可以选择用之。

 

2. 示例XML文档(holen.xml)

 

为了述说方便,先看一个XML文档,之后的操作均以此文档为基础。

 

 

holen.xml

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

    <!--This is a test for dom4j, holen, 2004.9.11-->

   

      

   

   

      

   

   

      

   

    O'Reilly

 

这是一个很简单的XML文档,场景是一个网上书店,有很多书,每本书有两个属性,一个是书名[title],一个为是否展示[show],最后还有一项是这些书的拥有者[owner]信息。

 

3. 建立一个XML文档

 

 

 

    /**

     * 建立一个XML文档,文档名由输入属性决定

     * @param filename 需建立的文件名

     * @return 返回操作结果, 0表失败, 1表成功

     */

    public int createXMLFile(String filename){

       /** 返回操作结果, 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节点 */

       Element bookElement = booksElement.addElement("book");

       /** 加入show属性内容 */

       bookElement.addAttribute("show","yes");

       /** 加入title节点 */

       Element titleElement = bookElement.addElement("title");

       /** 为title设置内容 */

       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节点 */

       Element ownerElement = booksElement.addElement("owner");

       ownerElement.setText("O'Reilly");

      

       try{

           /** 将document中的内容写入文件中 */

           XMLWriter writer = new XMLWriter(new FileWriter(new File(filename)));

           writer.write(document);

           writer.close();

           /** 执行成功,需返回1 */

           returnValue = 1;

       }catch(Exception ex){

           ex.printStackTrace();

       }

             

       return returnValue;

    }

 

说明:

Document document = DocumentHelper.createDocument();

通过这句定义一个XML文档对象。

 

Element booksElement = document.addElement("books");

通过这句定义一个XML元素,这里添加的是根节点。

Element有几个重要的方法:

l         addComment:添加注释

l         addAttribute:添加属性

l         addElement:添加子元素

 

最后通过XMLWriter生成物理文件,默认生成的XML文件排版格式比较乱,可以通过OutputFormat类的createCompactFormat()方法或createPrettyPrint()方法格式化输出,默认采用createCompactFormat()方法,显示比较紧凑,这点将在后面详细谈到。

 

生成后的holen.xml文件内容如下:

 

 

 

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

<!--This is a test for dom4j, holen, 2004.9.11-->O'Reilly

 

4. 修改XML文档

 

有三项修改任务,依次为:

l         如果book节点中show属性的内容为yes,则修改成no

l         把owner项内容改为Tshinghua,并添加date节点

l         若title内容为Dom4j Tutorials,则删除该节点

 

 

 

    /**

     * 修改XML文件中内容,并另存为一个新文件

     * 重点掌握dom4j中如何添加节点,修改节点,删除节点

     * @param filename 修改对象文件

     * @param newfilename 修改后另存为该文件

     * @return 返回操作结果, 0表失败, 1表成功

     */

    public int ModiXMLFile(String filename,String newfilename){

       int returnValue = 0;

       try{

           SAXReader saxReader = new SAXReader();

           Document document = saxReader.read(new File(filename));

           /** 修改内容之一: 如果book节点中show属性的内容为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");

              }  

           }

          

           /**

            * 修改内容之二: 把owner项内容改为Tshinghua

            * 并在owner节点中加入date节点,date节点的内容为2004-09-11,还为date节点添加一个属性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");

           }

          

           /** 修改内容之三: 若title内容为Dom4j Tutorials,则删除该节点 */

           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中的内容写入文件中 */

              XMLWriter writer = new XMLWriter(new FileWriter(new File(newfilename)));

              writer.write(document);

              writer.close();

              /** 执行成功,需返回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查找到相应内容。

 

通过setValue()、setText()修改节点内容。

 

通过remove()删除节点或属性。

 

5. 格式化输出和指定编码

 

默认的输出方式为紧凑方式,默认编码为UTF-8,但对于我们的应用而言,一般都要用到中文,并且希望显示时按自动缩进的方式的显示,这就需用到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();     

           /** 执行成功,需返回1 */

           returnValue = 1;    

       }catch(Exception ex){

           ex.printStackTrace();

       }

       return returnValue;

    }

 

说明:

 

OutputFormat format = OutputFormat.createPrettyPrint();

这句指定了格式化的方式为缩进式,则非紧凑式。

 

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

如果是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.         }   

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值