1 XML文件解析技术
Java解析XML文件有两个主要的实现方式:预加载DOM树,事件机制的SAX
2 预加载DOM树
2.1 设计思想
- 预加载DOM树是将整个XML文件数据读取到内存中,构造出一个DOM树对象,接着实现一套解析DOM树对象API。
2.2 具体实现
- 对于预加载DOM树,JAVA提供了两种实现JDOM,DOM4J。这两种方法的思路都是一样的,只不过一个是Java官方实现,一个是社区出的实现。
2.3 该思想有优点和缺点
- 优点:使用DOM时,XML文档的结构在内存中很清晰,元素与元素之间的关系完整保留在内存对象中。
- 缺点:如果XML文档非常大,将整个XML文档装在进内存容易造成内容溢出,。
2.4 案例
加载需要的jar包
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.0</version>
</dependency>
创建需要解析的xml
<books>
<book author="天蚕土豆">
<name>斗破苍穹</name>
<price>86</price>
</book>
<book author="萧潜">
<name>缥缈之旅</name>
<price>92</price>
</book>
<book author="萧鼎">
<name>诛仙</name>
<price>98</price>
</book>
<book author="天下霸唱">
<name>鬼吹灯</name>
<price>124</price>
</book>
<book author="辰东">
<name>神墓</name>
<price>128</price>
</book>
</books>
解析实例
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.util.List;
public class Dom4JTest {
public static void main(String[] args) throws DocumentException {
SAXReader saxReader = new SAXReader();
//document 加载执行xml文档获取Document对象
Document document = saxReader.read(Dom4JTest.class.getResource("/books.xml"));
//2.获取根元素的对象 -- books getRootElement 获取根元素
Element rootElement = document.getRootElement();
//每个元素的对象 都是Element对象
List<Element> elements = rootElement.elements();
//3.使用根元素的对象 对其他元素操作操作
//3.1获取所有的子元素对象 book
for (Element book : elements) {
//在循环内拿到了 每个 book 元素对象
//3.2获取book的属性值
String author = book.attributeValue("author");
//3.3获取book的子元素 name price
String name = book.element("name").getText();
String price = book.element("price").getText();
System.out.println(name + " " + author + " " + price);
}
}
}
2 事件机制的SAX
2.1 设计思想
- 一行一行的读取XML文件,每当读取到一个xml节点,就看看注册到该节点监听器事件是否被触发,如果有就触发该通知监听器去解析xml节点。解析xml过程中内存里不会保存任何数据。
2.2 具体实现
- 对于事件机制的SAX,JAVA 官方提供了实现
2.3 该思想有优点和缺点
- 优点:使用SAX不会占用大量内存来保存XML文档数据,效率高。
- 缺点:当解析一个元素时,上一个元素的信息已经丢弃,也就是说没有保存元素与元素之间的结构关系。
2.4 案例
创建需要解析的xml
<?xml version="1.0" encoding="UTF-8"?>
<PeopleList>
<People id="1">
<Name en='zhangsan'>张三</Name>
<Age>20</Age>
</People>
<People id="2">
<Name en='lisi'>李四</Name>
<Age>30</Age>
</People>
</PeopleList>
创建解析完成构建的model
public class People {
private String id;
private String name;
private String englishName;
private String age;
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 getEnglishName() {
return englishName;
}
public void setEnglishName(String englishName) {
this.englishName = englishName;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
创建解析器
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.ArrayList;
import java.util.List;
/**
* 解析器需要继承DefaultHandler类
*/
public class SaxHandler extends DefaultHandler {
//解析完成创建的model
private List<People> peoples = null;
//临时存储当前正在解析的People
private People people;
//临时存放挡墙解析的标签
private String currentTag = null;
//临时存放当前解析标签中字符 <>字符<>
private String currentValue = null;
//
private String nodeName = null;
public List<People> getPeoples() {
return peoples;
}
public SaxHandler(String nodeName) {
this.nodeName = nodeName;
}
/**
* 触发解析一个xml文件开始事件时调用
*/
@Override
public void startDocument() throws SAXException {
// TODO 当读到一个开始标签的时候,会触发这个方法
super.startDocument();
//初始化peoples
peoples = new ArrayList<People>();
}
/**
* 触发解析一个xml文件结束事件时调用
*/
@Override
public void endDocument() throws SAXException {
// TODO 自动生成的方法存根
super.endDocument();
}
/**
* 触发解析一个xml标签开始事件时调用
* @param uri
* @param localName
* @param name 当前标签的名称
* @param attributes 标签中的属性
* @throws SAXException
*/
@Override
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
// TODO 当遇到文档的开头的时候,调用这个方法
super.startElement(uri, localName, name, attributes);
if (name.equals(nodeName)) {
people = new People();
}
if (attributes != null && people != null) {
for (int i = 0; i < attributes.getLength(); i++) {
if(attributes.getQName(i).equals("id")){
people.setId(attributes.getValue(i));
}
else if(attributes.getQName(i).equals("en")){
people.setEnglishName(attributes.getValue(i));
}
}
}
currentTag = name;
}
/**
* 触发解析一个xml标签结束事件时调用
* @param uri
* @param localName
* @param name 当前标签的名称
* @throws SAXException
*/
@Override
public void endElement(String uri, String localName, String name)
throws SAXException {
// TODO 在遇到结束标签的时候,调用这个方法
super.endElement(uri, localName, name);
if (name.equals(nodeName)) {
peoples.add(people);
}
}
/**
* 触发解析一个xml标签中字符调用(startElement触发之后endElement触发之前)
* @param ch xml文档完整字符
* @param start 当前标签中字符在ch开始位置
* @param length 当前标签中字符的长度
* @throws SAXException
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// TODO 这个方法用来处理在XML文件中读到的内容
super.characters(ch, start, length);
if (currentTag != null && people != null) {
currentValue = new String(ch, start, length);
if (currentValue != null && !currentValue.trim().equals("") && !currentValue.trim().equals("\n")) {
if(currentTag.equals("Name")){
people.setName(currentValue);
}
else if(currentTag.equals("Age")){
people.setAge(currentValue);
}
}
}
currentTag = null;
currentValue = null;
}
}
测试代码
import java.util.List;
public class SaxTest {
public static void main(String[] args) throws Exception {
try {
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser parser = spf.newSAXParser();
SaxHandler handler = new SaxHandler("People");
parser.parse(Dom4JTest.class.getResource("/People.xml").openStream(), handler);
List<People> peopleList = handler.getPeoples();
for(People people : peopleList){
System.out.println(people.getId()+"\t"+people.getName()+"\t"+people.getEnglishName()+"\t"+people.getAge());
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
网友评论