14XML解析
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及中文问题
本节主要讨论了用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解析的更多相关文章
- 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新
本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...
- .NET Core中的认证管理解析
.NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...
- Html Agility Pack 解析Html
Hello 好久不见 哈哈,今天给大家分享一个解析Html的类库 Html Agility Pack.这个适用于想获取某网页里面的部分内容.今天就拿我的Csdn的博客列表来举例. 打开页面 用Fir ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例
前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...
- Asp.Net WebApi核心对象解析(下篇)
在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...
- 【知识必备】内存泄漏全解析,从此拒绝ANR,让OOM远离你的身边,跟内存泄漏say byebye
一.写在前面 对于C++来说,内存泄漏就是new出来的对象没有delete,俗称野指针:而对于java来说,就是new出来的Object放在Heap上无法被GC回收:而这里就把我之前的一篇内存泄漏的总 ...
- SQL Server 数据加密功能解析
SQL Server 数据加密功能解析 转载自: 腾云阁 https://www.qcloud.com/community/article/194 数据加密是数据库被破解.物理介质被盗.备份被窃取的最 ...
随机推荐
- android开发真机调试 相关东东
android开发真机调试 相关东东 我们做android开发的时候,可以用模拟器,也可以真机调试,但是电脑配置不高的话,模拟器,真的是慢的有的一说,所以我一直倾向于用真机调试,但是问题也就来了,模拟 ...
- css ios H5页面web页面 上下滑动卡顿问题解决方案
原因1: html,body{ height: 100%; } 删除上述代码即可. 其他原因: *{ -webkit-overflow-scrolling: touch; } 增加上述代码.
- 如何理解scrapy Selector
1 scrapy Selector是什么 Selector对象本质上是对DOM tree的子树的抽象,这种抽象的目的是用于定位我们感兴趣的node.比如某次http response是一棵完整的DOM ...
- Android 的坑一 :android.content.res.Resources$NotFoundException: String resource ID #0x0 找不到资源文件ID #0x0
原因分析如下: 遇到这种情况,很有可能是把一个int型业务数据的 设置setText()或者类似的方法中, 这样Android系统就会主动去资源文件当中寻找, 但是它不是一个资源文件ID, 所以就会报 ...
- BS与CS的联系与区别。
C/S是Client/Server的缩写.服务器通常采用高性能的PC.工作站或小型机,并采用大型数据库系统,如Oracle.Sybase.Informix或 SQL Server.客户端需要安装专用的 ...
- luence全文检索(数据库检索)
注解:从数据库中查询所有数据然后放入luence中,然后在luence来检索 package com.zhu.demo; import java.io.IOException; import java ...
- BZOJ_2424_[HAOI2010]订货_最小费用最大流
BZOJ_2424_[HAOI2010]订货_最小费用最大流 Description 某公司估计市场在第i个月对某产品的需求量为Ui,已知在第i月该产品的订货单价为di,上个月月底未销完的单位产品要付 ...
- GitLab: API is not accessibl
git push -u origin masterGitLab: API is not accessiblefatal: Could not read from remote repository. ...
- [转]c++中的string常用函数用法总结
标准c++中string类函数介绍 注意不是CString之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必 担心内存是否足够.字符串长度等等,而且作为 ...
- C#上机作业及代码Question2
第二题某文件名为"*.txt",其中*可能由若干个英文单词组成.将此文件名改为"*.dat",并且单词之间用下划线连接,例如: helloworld.txt,改 ...