XML是一种通用的数据交换格式,它的平台无关性、语言无关性、系统无关性、给数据集成与交互带来了极大的方便。XML在不同的语言环境中解析方式都是一样的,只不过实现的语法不同而已。
一、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分析器还是有很广泛的使用价值的。
优点:
1、形成了树结构,有助于更好的理解、掌握,且代码容易编写。
2、解析过程中,树结构保存在内存中,方便修改。
缺点:
1、由于文件是一次性读取,所以对内存的耗费比较大。
2、如果XML文件比较大,容易影响解析性能且可能会造成内存溢出。
DOM解析示例:
项目目录结构
1.DOM解析
TestXML.java文件
import java.io.FileReader;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
//采用DOM进行解析
//DOM的读取时是将XML整个文件装载成DOM树,即使文档中有不需要的信息时也会被装载进来,在大多数的时候DOM是非常方便好用的。
public class TestXMl {
public static void main(String[] args) {
// 文档构建器的工厂
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// 得到XML文档构建器
try {
DocumentBuilder db = dbf.newDocumentBuilder();
// 1.得到XML文档对象
// 当test.xml放在本项目的根目录时(和src bin同一目录下时)
// db.parse("test.xml");
// 当test.xml放在bin目录下时
String path = FileReader.class.getResource("/").getFile();
/// System.out.println(path);
// 导入的是org.w3c.dom.Document;
Document doc = db.parse(path + "test.xml");
// 得到文档根节点
Element root = doc.getDocumentElement();
String rootName = root.getNodeName();
System.out.println(rootName);
NodeList list = doc.getElementsByTagName("People");
// 2.获取XML中的节点
System.out.println("当前有几个People:" + list.getLength());
// 3.得到节点里面的有用信息
for (int i = 0; i < list.getLength(); i++) {
Element peopleElement = (Element) list.item(i);
String id = peopleElement.getAttribute("id"); // 获取id的属性值
System.out.println("id:" + id);
// 遍历当前元素的子节点
NodeList childNodeList = peopleElement.getChildNodes();
// test.xml中一个People元素下有Name和Age两个标签,但是它把回车也算作一个节点,所以打印出来是五个
// 第一个是没有回车的,第二个有
System.out.println("子节点个数:" + childNodeList.getLength());
// 判断这些子节点中的元素是不是有效的元素,即不为回车
for (int j = 0; j < childNodeList.getLength(); j++) {
// 判断是不是元素,有标签的,若是元素才把它转换为元素
if (childNodeList.item(j) instanceof Element) {
Element cElement = (Element) childNodeList.item(j);
String tagName = cElement.getTagName();
String content = cElement.getTextContent();
System.out.println(tagName + ":" + content);
}
}
}
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2.往XML文件中写入的是Document对象
Write.java文件
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
//由对象到文件,把document对象保存到文件中
//XML是磁盘文件,DOM是内存对象。
//往XML文件中写入的是Document对象,所以要编辑XML文件,实际上编辑的是Document文档对象。
public class WriteXML {
public static void main(String[] args) {
//创建一个document,通过builder创建
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.newDocument();
//通过document创建节点Element
Element stuEle = doc.createElement("Student");
stuEle.setAttribute("stuNo","S1001");
//给stuEle添加子节点
Element nameEle = doc.createElement("Name");
//方式一:创建一个文本节点
/*Text txtName = doc.createTextNode("zhangsan");
nameEle.appendChild(txtName);*/
//方式二:直接添加文本
nameEle.setTextContent("zhangsan");
Element ageEle = doc.createElement("Age");
ageEle.setTextContent("20");
stuEle.appendChild(nameEle);
stuEle.appendChild(ageEle);
//将Element对象添加到document中
doc.appendChild(stuEle);
//将document对象保存到硬盘文件xml中
//通过transformer进行保存
TransformerFactory tf = TransformerFactory.newInstance();
Transformer former = tf.newTransformer();
former.transform(new DOMSource(doc), new StreamResult("stu.xml"));
System.out.println("生成xml成功...");
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
test.xml
<?xml version="1.0" encoding="UTF-8"?>
<PeopleList>
<People id="1">
<Name en="zhangsan">张三</Name>
<Age>20</Age>
<Address>苏州</Address>
</People>
<People id="2">
<Name en="lisi">李四</Name>
<Age>39</Age>
<Address>常州</Address>
</People>
<People id="3">
<Name en="wangwu">王五</Name>
<Age>14</Age>
<Address>杨州</Address>
</People>
<People id="4">
<Name en="zhaowu">赵武</Name>
<Age>31</Age>
<Address>贵州</Address>
</People>
<People id="5">
<Name en="sunliu">孙刘</Name>
<Age>26</Age>
<Address>广州</Address>
</People>
</PeopleList>
二、SAX解析
SAX的全称是Simple APIs for XML,也即XML简单应用程序接口。与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式。当使用SAX分析器对XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问,因而SAX接口也被称作事件驱动接口。
优点:
1、采用事件驱动模式,对内存耗费比较小。
2、适用于只处理XML文件中的数据时。
缺点:
1、编码比较麻烦。
2、很难同时访问XML文件中的多处不同数据。
SAX解析示例
XMLHandler.java
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class XMLHandler extends DefaultHandler {
private String value; //读取到的文本
private People people; //临时存放的一个人
private List<People> peopleList;
public List<People> getPeopleList() {
return peopleList;
}
//当读到文档开始处触发事件,该方法只执行一次
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
super.startDocument();
System.out.println("开始执行startDocument,开始读取xml文档");
peopleList = new ArrayList<People>();
}
//当读到文档结束处触发事件,该方法只执行一次
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
super.endDocument();
System.out.println("开始执行endDocument,结束读取xml文档");
}
//当读到元素开始处触发事件
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
super.startElement(uri, localName, qName, attributes);
System.out.println("开始执行startElement,开始读取xml文档的标签,该标签为:"+qName);
if("People".equals(qName)) {
people = new People();
System.out.println("当前people有属性"+attributes.getLength());
for(int i = 0;i<attributes.getLength();i++) {
//获取当前属性名
if("id".equals(attributes.getQName(i))) {
people.setId(attributes.getValue(i));
}
}
}
}
//当读到元素结束处触发事件
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
// TODO Auto-generated method stub
super.endElement(uri, localName, qName);
System.out.println("开始执行endElement,结束读取xml文档的标签,该标签为:"+qName);
if("People".equals(qName)) {
peopleList.add(people);
people = null;
}else if("Name".equals(qName)) { //读到Name的结束标签
people.setName(value);
}else if("Age".equals(qName)) {
people.setAge(value);
}
}
//读到内容时触发事件
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// TODO Auto-generated method stub
super.characters(ch, start, length);
value = new String(ch,start,length);
System.out.println("当前读到的文本是:"+value);
}
}
ReadXMLBySAX.java
import java.io.IOException;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
//SAX解析
//流读取的机制(SAX),Document的读取在内部也是使用流的机制去读的。
//流读取的机制是只负责读取,不进行存储,但是会给出一定的关键的事件,提示你进行相应的保存操作。
public class ReadXMLBySAX {
public static void main(String[] args) {
//得到saxParser
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
SAXParser parser = factory.newSAXParser();
XMLHandler handler = new XMLHandler();
//通过saxParse接卸器的parse方法,解析xml,parse需要一个处理器,handler
parser.parse("test.xml", handler);
List<People> list = handler.getPeopleList();
System.out.println("一共读取倒了"+list.size()+"个人");
for(People people : list) {
System.out.println(people);
}
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
People.java
public class People {
private String id;
private String name;
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 getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public People(String id, String name, String age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public People() {
super();
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "Student[id="+id+",name="+name+",age="+age+"]";
}
}