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

Attribute定义了XML的属性

Branch

Branch为能够包含子节点的节点如XML元素(Element)和文档(Docuemnts)定义了一个公共的行为,

CDATA

CDATA 定义了XML CDATA 区域

CharacterData

CharacterData是一个标识借口,标识基于字符的节点。如CDATA,Comment, Text.

Comment

Comment 定义了XML注释的行为

Document

定义了XML文档

DocumentType

DocumentType 定义XML DOCTYPE声明

Element

Element定义XML 元素

ElementHandler

ElementHandler定义了 Element 对象的处理器

ElementPath

被   ElementHandler 使用,用于取得当前正在处理的路径层次信息

Entity

Entity定义 XML entity

Node

Node为所有的dom4j中XML节点定义了多态行为

NodeFilter

NodeFilter 定义了在dom4j节点中产生的一个滤镜或谓词的行为(predicate)

ProcessingInstruction

ProcessingInstruction 定义 XML 处理指令.

Text

Text 定义XML 文本节点.

Visitor

Visitor 用于实现Visitor模式.

XPath

XPath 在分析一个字符串后会提供一个XPath 表达式

表 10.1

看名字大致就知道它们的涵义如何了。要想弄懂这套接口,关键的是要明白接口的继承关系,如下图所示,大部分接口都是由Node继承来的。

  • 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

表 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及中文问题

本节主要讨论了用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解析包,性能优异,开发便捷。

14XML解析的更多相关文章

  1. 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

    本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...

  2. .NET Core中的认证管理解析

    .NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...

  3. Html Agility Pack 解析Html

    Hello 好久不见 哈哈,今天给大家分享一个解析Html的类库 Html Agility Pack.这个适用于想获取某网页里面的部分内容.今天就拿我的Csdn的博客列表来举例. 打开页面  用Fir ...

  4. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  5. 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

    上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...

  6. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  7. Asp.Net WebApi核心对象解析(下篇)

    在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...

  8. 【知识必备】内存泄漏全解析,从此拒绝ANR,让OOM远离你的身边,跟内存泄漏say byebye

    一.写在前面 对于C++来说,内存泄漏就是new出来的对象没有delete,俗称野指针:而对于java来说,就是new出来的Object放在Heap上无法被GC回收:而这里就把我之前的一篇内存泄漏的总 ...

  9. SQL Server 数据加密功能解析

    SQL Server 数据加密功能解析 转载自: 腾云阁 https://www.qcloud.com/community/article/194 数据加密是数据库被破解.物理介质被盗.备份被窃取的最 ...

随机推荐

  1. android开发真机调试 相关东东

    android开发真机调试 相关东东 我们做android开发的时候,可以用模拟器,也可以真机调试,但是电脑配置不高的话,模拟器,真的是慢的有的一说,所以我一直倾向于用真机调试,但是问题也就来了,模拟 ...

  2. css ios H5页面web页面 上下滑动卡顿问题解决方案

    原因1: html,body{ height: 100%; } 删除上述代码即可. 其他原因: *{ -webkit-overflow-scrolling: touch; } 增加上述代码.

  3. 如何理解scrapy Selector

    1 scrapy Selector是什么 Selector对象本质上是对DOM tree的子树的抽象,这种抽象的目的是用于定位我们感兴趣的node.比如某次http response是一棵完整的DOM ...

  4. Android 的坑一 :android.content.res.Resources$NotFoundException: String resource ID #0x0 找不到资源文件ID #0x0

    原因分析如下: 遇到这种情况,很有可能是把一个int型业务数据的 设置setText()或者类似的方法中, 这样Android系统就会主动去资源文件当中寻找, 但是它不是一个资源文件ID, 所以就会报 ...

  5. BS与CS的联系与区别。

    C/S是Client/Server的缩写.服务器通常采用高性能的PC.工作站或小型机,并采用大型数据库系统,如Oracle.Sybase.Informix或 SQL Server.客户端需要安装专用的 ...

  6. luence全文检索(数据库检索)

    注解:从数据库中查询所有数据然后放入luence中,然后在luence来检索 package com.zhu.demo; import java.io.IOException; import java ...

  7. BZOJ_2424_[HAOI2010]订货_最小费用最大流

    BZOJ_2424_[HAOI2010]订货_最小费用最大流 Description 某公司估计市场在第i个月对某产品的需求量为Ui,已知在第i月该产品的订货单价为di,上个月月底未销完的单位产品要付 ...

  8. GitLab: API is not accessibl

    git push -u origin masterGitLab: API is not accessiblefatal: Could not read from remote repository. ...

  9. [转]c++中的string常用函数用法总结

    标准c++中string类函数介绍 注意不是CString之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必 担心内存是否足够.字符串长度等等,而且作为 ...

  10. C#上机作业及代码Question2

    第二题某文件名为"*.txt",其中*可能由若干个英文单词组成.将此文件名改为"*.dat",并且单词之间用下划线连接,例如: helloworld.txt,改 ...