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 数据加密是数据库被破解.物理介质被盗.备份被窃取的最 ...
随机推荐
- 华为OJ:数字颠倒
将数字转成一个字符串即可了. import java.util.Scanner; public class convertNumber { public static void main(String ...
- jquery.validate自己定义验证--成功提示与择要提示
1. 自己定义验证--成功提示 1) 加入选项 errorClass: "unchecked". validClass: "checked", errorEle ...
- SQLServer2012连接数据库报错
尝试读取或写入受保护的内存 这通常指示其他内... CMD 输入 netsh winsock reset,重启计算机即可
- 容器HashSet原理(学习)
一.概述 使用HashMap存储,非线程安全: 二.实现 HashSet 底层使用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调 ...
- linux 点命令
cat a date . a Mon Jun :: CST linux .(点命令):读取并且在当前的shell中执行文件中的命令
- YTU 2898: C-Z型变换
2898: C-Z型变换 时间限制: 1 Sec 内存限制: 128 MB 提交: 53 解决: 15 题目描述 让我们来玩个Z型变换的游戏,游戏的规则如下: 给你一个字符串,将它以Z字型的形状不 ...
- Python基础第六天
一.内容 二.练习 练习1 题目:文件的增删改查 图示: 代码: import os def add(data): content = data[1] # 文件内容 file_name = data[ ...
- clc和clear命令的使用
clc命令是用来清除命令窗口的内容,这点不用多说.不管开启多少个应用程序,命令窗口只有一个,所以clc无论是在脚本m文件或者函数m文件调用时,clc命令都会清除命令窗口的内容.clear命令可以用来清 ...
- (前缀和 内存分配)51NOD 1081 子段求和
给出一个长度为N的数组,进行Q次查询,查询从第i个元素开始长度为l的子段所有元素之和. 例如,1 3 7 9 -1,查询第2个元素开始长度为3的子段和,1 {3 7 9} -1.3 + 7 + 9 ...
- 最大加权矩形 luogu1719
题目链接:https://www.luogu.org/problemnew/show/P1719 这道题挺好做的 又是一道练前缀和的题 #include <bits/stdc++.h> # ...