Java解析XML
本文介绍了使用JAXP和DOM4J解析java的方法.
编辑者:洋葱
引用来源
http://inotgaoshou.iteye.com/blog/1012188
http://developer.51cto.com/art/200903/117512.htm
http://baike.baidu.com/link?url=JKEP_Z5D0HWgDW0kHYKpwRTU3tyGeLooE94744iYIAItwTKK2yQREqoqkLEEqez6QK9vGLWpH0AXTkF_ARWvLa
转载请注明所有引用地址.
一.XML解析方式
1.DOM解析
DOM的全称是Document Object Model,也即文档对象模型。在应用程序中,基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称DOM树),应用程序正是通过 对这个对象模型的操作,来实现对XML文档数据的操作。通过DOM接口,应用程序可以在任何时候访问XML文档中的任何一部分数据,因此,这种利用DOM 接口的机制也被称作随机访问机制。
DOM接口提供了一种通过分层对象模型来访问XML文档信息的方式,这些分层对象模型依据XML的文档 结构形成了一棵节点树。无论XML文档中所描述的是什么类型的信息,即便是制表数据、项目列表或一个文档,利用DOM所生成的模型都是节点树的形式。也就 是说,DOM强制使用树模型来访问XML文档中的信息。由于XML本质上就是一种分层结构,所以这种描述方法是相当有效的。
DOM树所提 供的随机访问方式给应用程序的开发带来了很大的灵活性,它可以任意地控制整个XML文档中的内容。然而,由于DOM分析器把整个XML文档转化成DOM树 放在了内存中,因此,当文档比较大或者结构比较复杂时,对内存的需求就比较高。而且,对于结构复杂的树的遍历也是一项耗时的操作。所以,DOM分析器对机 器性能的要求比较高,实现效率不十分理想。不过,由于DOM分析器所采用的树结构的思想与XML文档的结构相吻合,同时鉴于随机访问所带来的方便,因 此,DOM分析器还是有很广泛的使用价值的。
2.SAX 解析
SAX的全称是Simple APIs for XML,也即XML简单应用程序接口。与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式。当使用SAX分析器对 XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问,因而SAX接口也被称作事件 驱动接口。
二.使用JAXP解析XML
/**
1.DOM生成和解析XML文档
为 XML 文档的已解析版本定义了一组接口。
解析器读入整个文档,然后构建一个驻留内存的树结构,然后代码就可以使用 DOM 接口来操作这个树结构。
优点:整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能;
缺点:将整个文档调入内存(包括无用的节点),浪费时间和空间;
使用场合:一旦解析了文档还需多次访问这些数据;硬件资源充足(内存、CPU)。
对XML文档的操作
1.获取/添加/修改/删除节点值
2.获取/设置/修改/删除属性值
3.层次遍历节点树
*/
public class DomDemo implements XmlDocument {
public static void main(String[] args){
String fileName="book.xml";
DomDemo dom=new DomDemo();
dom.parserXml(fileName);
dom.init();
dom.createXml("book.out.xml");
}
//文档对象
private Document document;
/**
创建一个空的文档对象
*/
public void init() {
try {
//构建一个工厂
DocumentBuilderFactory factory = DocumentBuilderFactory .newInstance();
//新建一个实例
DocumentBuilder builder = factory.newDocumentBuilder();
//获取文档对象
this.document = builder.newDocument();
} catch (ParserConfigurationException e) {
System.out.println(e.getMessage());
}
}
/**
创建一个XML文件
*/
public void createXml(String fileName) {
//创建一个元素,并作为根节点
Element root = this.document.createElement("books");
this.document.appendChild(root);
//创建一个节点
Element book = this.document.createElement("book");
//创建一个子节点,并设置子节点的文本内容
Element bookName = this.document.createElement("书名");
bookName.appendChild(this.document.createTextNode("Java编程思想第4版"));
book.appendChild(bookName);
Element price = this.document.createElement("定价");
//设置属性
price.setAttribute("单位", "元");
price.appendChild(this.document.createTextNode("108.00"));
book.appendChild(price);
//如上
Element author = this.document.createElement("作者");
author.setAttribute("性别", "男");
author.appendChild(this.document.createTextNode("Bruce Eckel"));
book.appendChild(author);
//如上
Element isbnNo = this.document.createElement("ISBN编号");
isbnNo.appendChild(this.document.createTextNode("9787111213826"));
book.appendChild(isbnNo);
root.appendChild(book);
//保存
save(document,fileName, "gbk");
}
/**
从文件解析XML文档
*/
public void parserXml(String fileName) {
try {
// 创建工厂,构建示例,加载文件,获取文档树对象
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(fileName);
// 获取所有直接子节点
NodeList books = document.getChildNodes();
// 遍历,第一层
for (int i = 0; i < books.getLength(); i++) {
Node book = books.item(i);
System.out.println(book.getNodeName());
NodeList bookInfo = book.getChildNodes();
// 遍历,第二层
for (int j = 0; j < bookInfo.getLength(); j++) {
Node node = bookInfo.item(j);
System.out.println("\t"+node.getNodeName());
NodeList bookMeta = node.getChildNodes();
// 遍历,第三层
for (int k = 0; k < bookMeta.getLength(); k++) {
System.out.print("\t\tnode>>"
+ bookMeta.item(k).getNodeName() + ":"
+ bookMeta.item(k).getTextContent());
// 输出示例 书名:Java编程思想第4版
/**
* 获取属性,而且可以设置属性
*/
NamedNodeMap map = bookMeta.item(k).getAttributes();
if (map != null) {
for (int l = 0; l < map.getLength(); l++) {
Node att = map.item(l);
System.out.println(" "+att.getNodeName() + "="
+ att.getTextContent());
//设置属性
att.setTextContent("changed");
}
}
}
}
}
/**
* 通过输出结果我们可以发现,JAVA使用DOM解析时,<标签>与<标签>之间也是节点
*/
System.out.println("解析完毕");
//将修改的结果保存
save(document,fileName, "gbk");
} catch (FileNotFoundException e) {
System.out.println(e.getMessage());
} catch (ParserConfigurationException e) {
System.out.println(e.getMessage());
} catch (SAXException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
public void save(Document document, String fileName, String encoding) {
// System.out.println("encoding="+document.getXmlEncoding());
// 实例化转换器工厂
TransformerFactory tf = TransformerFactory.newInstance();
try {
// 实例一个转换器
Transformer transformer = tf.newTransformer();
// 构建一个文档源
DOMSource source = new DOMSource(document);
// 设置字符编码
transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
// 设置缩排
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
PrintWriter pw = new PrintWriter(new FileOutputStream(fileName));
StreamResult result = new StreamResult(pw);
// 通过转换器将文档树源写入文件
transformer.transform(source, result);
System.out.println("XML文件保存成功!");
} catch (TransformerConfigurationException e) {
System.out.println(e.getMessage());
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
} catch (FileNotFoundException e) {
System.out.println(e.getMessage());
} catch (TransformerException e) {
System.out.println(e.getMessage());
}
}
}
//
/**
2.SAX生成和解析XML文档
为解决DOM的问题,出现了SAX。SAX ,事件驱动。
当解析器发现元素开始、元素结束、文本、文档的开始或结束等时,发送事件,程序员编写响应这些事件的代码,保存数据。
优点:
不用事先调入整个文档,占用资源少;
SAX解析器代码比DOM解析器代码小,适于Applet,下载。
缺点:
不是持久的;事件过后,若没保存数据,那么数据就丢了;
无状态性;从事件中只能得到文本,但不知该文本属于哪个元素;
使用场合:Applet;只需XML文档的少量内容,很少回头访问;机器内存少;
*/
public class SaxDemo implements XmlDocument {
public static void main(String[] args){
SaxDemo demo=new SaxDemo();
String fileName="book.out.xml";
demo.parserXml(fileName);
}
public void createXml(String fileName) {
System.out.println("<<"+fileName+">>");
}
//解析
public void parserXml(String fileName) {
//实例化一个工厂
SAXParserFactory saxfac = SAXParserFactory.newInstance();
try {
//实例化一个解析器
SAXParser saxparser = saxfac.newSAXParser();
InputStream is = new FileInputStream(fileName);
//使用MySAXHandler处理文档
saxparser.parse(is, new MySAXHandler());
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void save(Document document, String fileName, String encoding) {
// TODO Auto-generated method stub
}
}
class MySAXHandler extends DefaultHandler {
boolean hasAttribute = false;
Attributes attributes = null;
//解析开始事件
public void startDocument() throws SAXException {
System.out.println("文档解析开始");
}
//解析结束事件
public void endDocument() throws SAXException {
System.out.println("文档解析结束");
}
//解析到一个元素的起始标签
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
System.out.println("elementStart> "+qName);
if (attributes.getLength() > 0) {
this.attributes = attributes;
this.hasAttribute = true;
}
}
//解析到一个元素的结束标签
public void endElement(String uri, String localName, String qName) throws SAXException {
//打印属性
if (hasAttribute && (attributes != null)) {
for (int i = 0; i < attributes.getLength(); i++) {
System.out.println("attr> "+attributes.getQName(0)+"="+ attributes.getValue(0));
}
}
System.out.println(qName+">elementEnd");
}
//解析到元素内容
public void characters(char[] ch, int start, int length) throws SAXException {
//输出内容
System.out.println("content> "+new String(ch, start, length));
}
}
三.使用Dom4j 解析XML
百度百科上有大量的说明,这里写一个很小的应用
/***
* 使用Dom4j操作XML文档.
* 操作列表:
* 加载,解析,读取,添加,修改,保存.
*/
public class Dom4jInstance {
public static void main(String[] args) throws DocumentException, IOException {
String outFile="Dom4jDemo.xml";
Dom4jInstance ins=new Dom4jInstance();
ins.load(outFile);
ins.iterator();
ins.addNode();
ins.save(outFile);
}
private Document doc=null;
//1.从文件加载XML文档
public void load(String fileName) throws DocumentException{
File file=new File(fileName);
if(!file.exists()){
System.out.println("文件不存在!");
return ;
}
SAXReader reader = new SAXReader();
doc= reader.read(file);
System.out.println("加载成功!");
}
//2.遍历xml
public void iterator(){
doc.accept(new MyVisitor());
}
private class MyVisitor extends VisitorSupport {
//访问元素
public void visit(Element element) {
System.out.println("\t"+element.getName());
}
//访问属性
public void visit(Attribute attr) {
System.out.print("\t"+attr.getName()+"="+attr.getValue()+" ");
}
//访问元素内值
public void visit(Text node) {
System.out.println("\t\t"+node.getText());
}
}
//3.使用XPath获取某个元素
public void update(String xpath){
List<Node> list=doc.selectNodes(xpath);
for(Node node : list){
System.out.println(node.getName()+"="+node.getText());
}
}
//4.添加一个节点并设置属性
public void addNode(){
List<Node> list=doc.selectNodes("//books/book");
for(Node n : list){
Element e=(Element)n;
e.addElement("出版社").addAttribute("地址", "北京").setText("清华大学出版社");
}
}
//5.选择编码格式并保存到文件
public void save(String outFile) throws IOException{
XMLWriter writer;
// 美化格式
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding(doc.getXMLEncoding());
writer = new XMLWriter(new FileOutputStream(outFile), format );
System.out.println("已写入文件"+outFile);
writer.write(doc);
}
}