Java操作XML的五种方式

[TOC]

1、了解XML

​ XML,即可扩展标记语言(Extensible Markup Language),标准通用标记语言的子集,一种用于标记电子文件使其具有结构性的标记语言。它可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 它非常适合万维网传输,提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。它和JSON都是一种数据交换格式。

作用:解析XML文档,创建XML文档。

2、什么是可扩展标记语言?

· 可扩展标记语言是一种很像超文本标记语言的标记语言。

· 它的设计宗旨是传输数据,而不是显示数据。

· 它的标签没有被预定义。您需要自行定义标签。

· 它被设计为具有自我描述性。

· 它是W3C的推荐标准。

3、解析XML文档的五种方式: 五种方法解析XML文档:Dom、SAX、JDOM、dom4j 、degister

准备xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<languages cat="it">
<lang id="1">
<name>Java</name>
<ide>Eclipse</ide>
</lang>
<lang id="2">
<name>Swift</name>
<ide>Xcode</ide>
</lang>
<lang id="3">
<name>c#</name>
<ide>Visual Studio</ide>
</lang>
</languages>

3.1、DOM

第一种:DOM的全称是Document Object Model,也即文档对象模型。在应用程序中,基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称DOM树),应用程序正是通过对这个对象模型的操作,来实现对XML文档数据的操作。通过DOM接口,应用程序可以在任何时候访问XML文档中的任何一部分数据,因此,这种利用DOM接口的机制也被称作随机访问机制。

3.1.1 dom读取xml文件

​ 读取代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public void readXML() throws ParserConfigurationException, IOException, SAXException {
//1.获取DocumentBuilder工厂实例
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
//2.获取解析器
DocumentBuilder builder = dbf.newDocumentBuilder();
//3.解析文件
Document document = builder.parse(this.getClass().getClassLoader().getResourceAsStream("xml/languages.xml"));
//获取根元素
Element root = document.getDocumentElement();
//获取属性
String cat = root.getAttribute("cat");
System.out.println("根元素为:"+root.getNodeName()+" 属性cat:"+cat);
//获取所有名字为lang的标签
NodeList langs = root.getElementsByTagName("lang");
int length = langs.getLength();
System.out.println("lang名称的节点长度为:"+length);
for (int i = 0; i < length; i++) {
Node node = langs.item(i);
//获取下面所有的子节点
NodeList childNodes = node.getChildNodes();
int len = childNodes.getLength();
System.out.println("第"+(i+1)+"个lang标签子节点长度:"+len);//长度为5(因为含有三个回车)
for (int j = 0; j < len; j++) {
Node item = childNodes.item(j);
//只对节点类型为ELEMENT_NODE的操作 回车的类型为TEXT_NODE
if(item.getNodeType()==Node.ELEMENT_NODE){
System.out.println(item.getNodeName()+"="+item.getTextContent());
}
}
}
}

3.1.2 dom方式创建xml

创建xml代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public void createXml() throws ParserConfigurationException, TransformerException {
//1.获取DocumentBuilder工厂实例
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
//2.获取解析器
DocumentBuilder builder = dbf.newDocumentBuilder();
//3.获取Document
Document document = builder.newDocument();
//创建节点
Element root = document.createElement("languages");
//创建属性
root.setAttribute("cat", "it");
//创建lang
Element lang = document.createElement("lang");
lang.setAttribute("id", "1");
Element name = document.createElement("name");
name.setTextContent("java");//设置文本内容
Element ide = document.createElement("ide");
ide.setTextContent("Eclipse");
//添加节点
lang.appendChild(name);
lang.appendChild(ide);
root.appendChild(lang);
document.appendChild(root);
//输出
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty("encoding", "UTF-8");
//写到字符串
StringWriter out = new StringWriter();
transformer.transform(new DOMSource(document),new StreamResult(out));
System.out.println(out.toString());
//写到文件
transformer.transform(new DOMSource(document), new StreamResult(new File("newxml.xml")));
}

3.2 、SAX

​ SAX介绍

  SAX的全称是Simple APIs for XML,也即XML简单应用程序接口。

  与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式。

  当使用SAX分析器对XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问,因而SAX接口也被称作事件驱动接口

  局限性:

  1. SAX分析器在对XML文档进行分析时,触发了一系列的事件,由于事件触发本身是有时序性的,因此,SAX提供的是一种顺序访问机制,对于已经分析过的部分,不能再倒回去重新处理。

  即,一旦经过了某个元素,我们没有办法返回去再去访问它。

  2. SAX分析器只做了一些简单的工作,大部分工作还要由应用程序自己去做。

  也就是说,SAX分析器在实现时,只是顺序地检查XML文档中的字节流,判断当前字节是XML语法中的哪一部分、是否符合XML语法,然后再触发相应的事件,而事件处理函数本身则要由应用程序自己来实现。

  同DOM分析器相比,SAX分析器缺乏灵活性。

  优势:

  然而,由于SAX分析器实现简单,对内存要求比较低,(SAX不必将整个XML文档加载到内存当中,因此它占据内存要比DOM小), 因此实现效率比较高。

  对于大型的XML文档来说,通常会用SAX而不是DOM。

  并且对于那些只需要访问XML文档中的数据而不对文档进行更改的应用程序来说,SAX分析器更为合适。

DefaultHandler类:

img

3.2.1 读取xml文件

标签的枚举类如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package org.wuqinghua.java.xml.sax;
/**
* Created by wuqinghua on 17/7/5.
*/
public enum TagName {
LANGUAGES("languages"),LANG("lang"), NAME("name"), IDE("ide"),NONE("none");
private String tagName;
TagName(String tagName) {
this.tagName = tagName;
}
public String getTagName() {
return tagName;
}
public static TagName transformer(String tagName) {
switch (tagName) {
case "languages":
return LANGUAGES;
case "lang":
return LANG;
case "name":
return NAME;
case "ide":
return IDE;
default:
return NONE;
}
}
}

将lang标签设计为一个对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package org.wuqinghua.java.xml.sax;
/**
* Created by wuqinghua on 17/7/5.
*/
public class Lang {
private String id;
private String name;
private String ide;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIde() {
return ide;
}
public void setIde(String ide) {
this.ide = ide;
}
@Override
public String toString() {
return "Lang{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", ide='" + ide + '\'' +
'}';
}
}

xml顺序执行的handler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package org.wuqinghua.java.xml.sax;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.ArrayList;
import java.util.List;
/**
* Created by wuqinghua on 17/7/5.
*/
public class SaxHandler extends DefaultHandler {
private List<Lang> langs = null;
private Lang lang = null;
private boolean isName = false;
private boolean isIde = false;
//文档开始触发
@Override
public void startDocument() throws SAXException {
super.startDocument();
}
//文档结束触发
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
//标签开始触发
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
TagName tagName = TagName.transformer(qName);
switch (tagName) {
case NONE:
break;
case LANGUAGES:
if (langs == null)
langs = new ArrayList<>();
break;
case LANG: //解析lang标签
lang = new Lang();
String id = attributes.getValue("id");
lang.setId(id);
break;
case NAME: //解析name标签
isName = true;
break;
case IDE: //解析ide标签
isIde = true;
break;
}
}
//标签结束触发
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (TagName.transformer(qName).equals(TagName.LANG)) {
langs.add(lang);
}
}
//标签中数据触发
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (isName) {
lang.setName(new String(ch, start, length));
isName = false;
} else if (isIde) {
lang.setIde(new String(ch, start, length));
isIde = false;
}
}
public List<Lang> getLangs() {
return langs;
}
}

读取xml

1
2
3
4
5
6
7
8
9
10
11
12
13
public void readXML() throws ParserConfigurationException, SAXException, IOException {
//1.获取SAX解析器的工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//2.获取SAX解析器
SAXParser saxParser = factory.newSAXParser();
//3.创建顺序读取xml的处理器
SaxHandler handler = new SaxHandler();
//4.解析xml
saxParser.parse(this.getClass().getClassLoader().getResourceAsStream("xml/languages" +
".xml"),handler);
System.out.println(handler.getLangs());
}

3.2.1 创建xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public void createXML() throws TransformerConfigurationException, SAXException {
//1.获取SAXTransformerFactory实例
SAXTransformerFactory factory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
//2.创建TransformerHandler实例
TransformerHandler transformerHandler = factory.newTransformerHandler();
//3.创建Transformer对象
Transformer transformer = transformerHandler.getTransformer();
//4、设置输出的xml属性,encoding为编码,indent是确保输出的xml文件能够自动换行
transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT,"yes");
//5、创建Result对象,将Result对象加载到TransHandler中
//注意:1、这一步必须在Transformer.setOutputProperty()之后,不然设置的xml属性将不生效
// 2、这一步也必须在TransformerHandler.startDocument()之前,不然会报错。
// 分析源码后发现,startDocument()会先判断result是否为空,为空则报错
Result result = new StreamResult("newxml.xml");
transformerHandler.setResult(result);
//6、创建属性Attribute对象
AttributesImpl attr = new AttributesImpl();
//7.开始写文件
transformerHandler.startDocument();
//8.写入根节点
attr.clear();
//设置属性
attr.addAttribute("","","cat","","it");
transformerHandler.startElement("","",TagName.LANGUAGES.getTagName(),attr);
//设置lang节点
attr.clear();
attr.addAttribute("","","id","","1");
transformerHandler.startElement("","",TagName.LANG.getTagName(),attr);
//设置name节点
attr.clear();;
transformerHandler.startElement("","",TagName.NAME.getTagName(),attr);
transformerHandler.characters("java".toCharArray(),0,"java".toCharArray().length);
transformerHandler.endElement("","",TagName.NAME.getTagName());
//设置ide
attr.clear();
transformerHandler.startElement("","",TagName.IDE.getTagName(),attr);
transformerHandler.characters("Eclipse".toCharArray(),0,"Eclipse".toCharArray().length);
transformerHandler.endElement("","",TagName.IDE.getTagName());
transformerHandler.endElement("","",TagName.LANG.getTagName());
transformerHandler.endElement("","",TagName.LANGUAGES.getTagName());
//9.结束
transformerHandler.endDocument();
}

3.3 JDom

JDOM是一个开源项目,它基于树型结构,利用Java的技术对XML文档实现解析、生成、序列化以及多种操作,用Java的数据类型来定义操作数据树的各个节点。

JDOM下载

jdom-2.0.4.jar下载: http://www.jdom.org/downloads/

3.3.1 读取xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public void readXML() throws JDOMException, IOException {
//1.获取JDom的解析器
SAXBuilder saxBuilder = new SAXBuilder();
//2.加载xml
Document document = saxBuilder.build(this.getClass().getClassLoader().getResourceAsStream("xml/languages" +
".xml"));
//3.获取根元素
Element rootElement = document.getRootElement();
System.out.println("根元素名称:"+rootElement.getName()+" 属性cat:"+rootElement.getAttributeValue
("cat"));
//4.获取根元素下的所有的子节点
List<Element> children = rootElement.getChildren();
for (int i = 0; i <children.size() ; i++) {
Element element = children.get(i);
System.out.println(element.getName()+" id:"+element.getAttribute("id").getValue());
List<Element> child = element.getChildren();
for (int j = 0; j < child.size(); j++) {
System.out.println(child.get(j).getName()+"="+child.get(j).getText());
}
}
}

3.3.2 创建xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public void createXml() throws TransformerException, IOException {
//1.创建文档
Document document = new Document();
//2.添加跟节点
Element root = new Element("languages");
root.setAttribute("cat","it");
document.setRootElement(root);
//3.添加子节点
Element lang = new Element("lang");
lang.setAttribute("id","1");
Element name = new Element("name");
name.setText("Java");
Element ide = new Element("ide");
ide.setText("Eclipse");
lang.addContent(name);
lang.addContent(ide);
root.addContent(lang);
//输出
// TransformerFactory factory = TransformerFactory.newInstance();
// Transformer transformer = factory.newTransformer();
// transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");
// transformer.setOutputProperty(OutputKeys.INDENT,"yes");
// transformer.transform(new JDOMSource(document),new StreamResult(new FileWriter("newxml" +
// ".xml")));
//输出
Format format = Format.getPrettyFormat();
format.setEncoding("UTF-8");
XMLOutputter out = new XMLOutputter();
out.setFormat(format);
out.output(document,new FileWriter("newxml.xml"));
}

3.4 DOM4J

​ dom4j的项目地址:http://sourceforge.net/projects/dom4j/?source=directory

  dom4j是一个简单的开源库,用于处理XML、 XPath和XSLT,它基于Java平台,使用Java的集合框架,全面集成了DOM,SAX和JAXP。

3.4.1 读取xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public void readXml() throws DocumentException {
//1.说去SAXReader对象
SAXReader reader = new SAXReader();
//2.获取Document对象
Document document = reader.read(this.getClass().getClassLoader().getResourceAsStream("xml/languages.xml"));
//3.获取根元素
Element rootElement = document.getRootElement();
System.out.println("根元素名称:"+rootElement.getName());
String cat = rootElement.attributeValue("cat");
System.out.println("属性为cat的值为:"+cat);
System.out.println("-------------------------");
//4.获取其下的子元素
List<Element> elements = rootElement.elements();
for (int i = 0; i < elements.size(); i++) {
Element element = elements.get(i);
System.out.println("第"+i+"个元素的名称:"+element.getName());
System.out.println("属性id为:"+element.attributeValue("id"));
List<Element> children = element.elements();
for (int j = 0; j < children.size(); j++) {
Element ele = children.get(j);
System.out.println(ele.getName()+"="+ele.getText());
}
System.out.println("-------------------------");
}
}

3.4.2 创建xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public void createXml() throws IOException {
//1.获取文档
Document document = DocumentHelper.createDocument();
//2.创建跟节点
Element languages = DocumentHelper.createElement("languages");
languages.addAttribute("cat","it");
document.setRootElement(languages);
//3.添加子节点
Element lang = languages.addElement("lang");
lang.addAttribute("id","1");
Element name = lang.addElement("name");
name.setText("Java");
Element ide = lang.addElement("ide");
ide.setText("Eclipse");
//输出
//输出到控制台
XMLWriter writer = new XMLWriter();
writer.write(document);
//输出到文件
OutputFormat format = new OutputFormat(" ",true);
XMLWriter out = new XMLWriter(new FileOutputStream("newxml.xml"),format);
out.write(document);
}

3.5 digester

digester原来为struts中解析xml的方式,由于其比较好,被apache单独拿出变为一个小型框架。

其使用的原理为sax。