XML解析
XML解析
DOM4J
DOM4J是dom4j.org出品的一个开源XML解析包Dom4j是一个易用的、开源的库,用于XML,XPath和XSLT的解析及相关应用。它应用于Java平台,采用了Java集合框架并完全支持DOM,SAX和JAXP。与其他一些XML解析包的比较,DOM4J的性能上存在明显优势,在多项测试中名列前茅。DOM4J使用起来非常简单。只要你了解基本的XML-DOM模型,就能使用。
10.2 DOM4J的接口
DOM4J最大的特色是使用大量的接口,它的主要接口都在org.dom4j这个包里定义:
| Attribute定义了XML的属性 |
| Branch为能够包含子节点的节点如XML元素(Element)和文档(Docuemnts)定义了一个公共的行为, |
| CDATA 定义了XML CDATA 区域 |
| CharacterData是一个标识借口,标识基于字符的节点。如CDATA,Comment, Text. |
| Comment 定义了XML注释的行为 |
| 定义了XML文档 |
| DocumentType 定义XML DOCTYPE声明 |
| Element定义XML 元素 |
| ElementHandler定义了 Element 对象的处理器 |
| 被 ElementHandler 使用,用于取得当前正在处理的路径层次信息 |
| Entity定义 XML entity |
| Node为所有的dom4j中XML节点定义了多态行为 |
| NodeFilter 定义了在dom4j节点中产生的一个滤镜或谓词的行为(predicate) |
| ProcessingInstruction 定义 XML 处理指令. |
| Text 定义XML 文本节点. |
| Visitor 用于实现Visitor模式. |
| XPath 在分析一个字符串后会提供一个XPath 表达式 |
表 10.1
看名字大致就知道它们的涵义如何了。要想弄懂这套接口,关键的是要明白接口的继承关系,如下图所示,大部分接口都是由Node继承来的。
|
表 10.2
10.3 下载与安装
可以到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异常,其他的包可以选择用之。
10.4 程序示例
10.4.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; } |
表10.3
其中,reader的read方法是重载的,可以从InputStream, File, Url等多种不同的源来读取。得到的Document对象就带表了整个XML。
10.4.2 取得Root节点
读取后的第二步,就是得到Root节点。熟悉XML的人都知道,一切XML分析都是从Root元素开始的。
public Element getR9ootElement(Document doc){ return doc.getRootElement(); } |
表10.4
10.4.3 遍历XML树
DOM4J提供至少3种遍历节点的方法:枚举(Iterator),递归,Visitor模式。通常我们使用枚举方式,详细见下例。
// 枚举所有子节点 Iterator i = root.elementIterator(); while(i.hasNext()) { Element element = (Element) i.next(); }
i = root.elementIterator(foo); // 枚举名称为foo的节点 while(i.hasNext()) { Element foo = (Element) i.next(); }
i = root.attributeIterator(); // 枚举属性 while(i.hasNext()) { Attribute attribute = (Attribute) i.next(); } |
表10.5
10.4.4 字符串与XML的转换
有时候经常要用到字符串转换为XML或反之,
// XML转字符串 Document document = ...; String text = document.asXML();
// 字符串转XML String text = “<person> <name>James</name> </person>”; Document document = DocumentHelper.parseText(text); |
表10.6
10.4.5 创建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; } |
表10.7
10.4.6 文件输出
一个简单的输出方法是将一个Document或任何的Node通过write方法输出
FileWriter out = new FileWriter( foo.xml ); document.write(out); |
表10.8
10.5 用
本节主要讨论了用dom4j解析XML的基础问题,包括建立XML文档,添加、修改、删除节点,以及(美化)输出和中文问题
10.5.1 建立一个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");
/** 加入第一个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; } |
例10.2
说明: Document document = DocumentHelper.createDocument(); 通过这句定义一个XML文档对象。
Element booksElement = document.addElement("books"); 通过这句定义一个XML元素,这里添加的是根节点。 |
Element有几个重要的方法:
- addComment:添加注释
- addAttribute:添加属性
- addElement:添加子元素
最后通过XMLWriter生成物理文件,默认生成的XML文件排版格式比较乱,可以通过OutputFormat类的createCompactFormat()方法或createPrettyPrint()方法格式化输出,默认采用createCompactFormat()方法,显示比较紧凑,这点将在后面详细谈到。
生成后的xml文件内容如下:
<?xml version="1.0" encoding="UTF-8"?> <books> <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> |
表10.9
10.5.2 修改XML文档
有三项修改任务,依次为:
a. 如果book节点中show属性的内容为yes,则修改成no
b. 把owner项内容改为Tshinghua,并添加date节点
c. 若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; } |
例10.3
说明: List list = document.selectNodes("/books/book/@show" ); list = document.selectNodes("/books/book"); 上述代码通过xpath查找到相应内容。 通过setValue()、setText()修改节点内容。 通过remove()删除节点或属性。 |
10.5.3 格式化输出和指定编码
默认的输出方式为紧凑方式,默认编码为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; } |
例10.4
说明: OutputFormat format = OutputFormat.createPrettyPrint(); 这句指定了格式化的方式为缩进式,则非紧凑式。
format.setEncoding("GBK"); 指定编码为GBK。
XMLWriter writer = new XMLWriter(new FileWriter(new File(filename)),format); 这与前面两个方法相比,多加了一个OutputFormat对象,用于指定显示和编码方式。
|
10.6 总结
- 扩展标记语言XML是一种简单的数据存储语言,结构严谨,使用方便,在当前WEB开发领域所起的作用越来越大,应用越来越广泛。
- DOM4J是dom4j.org出品的一个开源XML解析包,性能优异,开发便捷。