XML解析的两种方式比较DOM与Sax
xml文件:
DOM解析
将整个XML数据转换成一个树形对象[Document对象]
将XML中的标签,属性,文本都作为一个结点对象
在解析XML的时候,先将整个xml一次性读入到内存中,
封装成树对象再进行操作
public class XmlDemo {
/**
* 使用JAXP工具的DOM方式解析XML
* @param args
*/
public static void main(String args[]) throws Exception{
String path = "C:\\Users\\Administrator\\Desktop\\stus.xml";
File f = new File(path);
//1.创建一个DOM解析器工厂
DocumentBuilderFactory factory =DocumentBuilderFactory.newInstance();
//2.通过工厂生产一个解析器对象
DocumentBuilder builder = factory.newDocumentBuilder();
//3.解析指定的XML文件
Document dom = builder.parse(f);
//从Document树上提取数据
// Node node = dom.getFirstChild();
// System.out.println(node);
//获得文档的根节点
Element root = dom.getDocumentElement();
System.out.println("根节点:"+root);
//由于是一个元素节点,可以获得其所有的儿子节点
NodeList list = root.getChildNodes();
//遍历list
for(int i=0;i<list.getLength();i++){
//取得一个子节点
Node node = list.item(i);
//如果子节点是一个元素节点,才需要处理
if(node instanceof Element) {
//将node强制转换成Element
Element stu =(Element)node;
//获得stu的属性
String num = stu.getAttribute("num");
System.out.println("num:"+num);
//获得stu的子节点
NodeList childList = stu.getChildNodes();
for(int j=0;j<childList.getLength();j++){
Node n = childList.item(j);
if(n instanceof Element) {
Element element = (Element)n;
//获得节点名字
String nodeName = element.getNodeName();
//获得节点中包含的文本
String content = element.getTextContent();
System.out.println(nodeName+":"+content);
}
}
}
}
}
}
DOM方式解析的优点:
由于所有的结点都在内存的Document对象中,支持随机访问
DOM方式解析的缺点:
由于所有的数据是一次性读入到内存中的,对于比较大的xml数据,非常占内存
SAX解析:
顺序解析,事件驱动
按顺序一边读取数据,一边进行解析,在读取数据的时候会触发一定的事件,每触发一次,就可以做一次处理
public class SaxPaserXml {
public static void main(String[] args) throws Exception{
String path = "xml/stus.xml";
File f = new File(path);
//1.创建Sax解析器工厂
SAXParserFactory factory =SAXParserFactory.newInstance();
//2.通过工厂生产一个sax解析器对象
SAXParser saxPaser = factory.newSAXParser();
//3.创建事件处理器对象
DefaultHandler handler = new MyHander();
//4.开始解析
saxPaser.parse(f,handler);
}
}
创建存放数据的对象
public class Student {
private int num;
private String name;
private int age;
private char sex;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Student{" +
"num=" + num +
", name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
}
创建事件处理器类:DefaultHandler
/**
* Sax的事件处理器,继承DefaultHandler
* 需要重写DefaultHandler的事件处理方法
* 事件处理器中的方法是通过事件触发自动调用的
*
*/
public class MyHander extends DefaultHandler {
//创建一个数组对象
ArrayList<Student> list = new ArrayList<>();
String msg=null;
Student stu =null;
//开始解析文档
@Override
public void startDocument() throws SAXException {
System.out.println("startDocument");
}
//解析到开始标签,需要处理标签中的属性
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if(qName.equals("stu")) {
//当开始标签是stu的时候,就需要创建一个学生对象
stu = new Student();
//设置学生对象的num属性
String snum = attributes.getValue("num");
//需要先将字符串的num转换成int类型
int num = Integer.parseInt(snum);
stu.setNum(num);
}
}
//解析到文本内容
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
msg = new String(ch,start,length);
}
//解析到结束标签
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
switch (qName){
case "name":
stu.setName(msg);
break;
case "age":
int age = Integer.parseInt(msg);
stu.setAge(age);
break;
case "sex":
stu.setSex(msg.trim().charAt(0));
break;
case "stu":
//如果结束标签是stu,就将学生对象保存到list中
list.add(stu);
break;
}
}
//解析文档结束
@Override
public void endDocument() throws SAXException {
//输出list
for(Student stu:list){
System.out.println(stu);
}
}
}
Sax的优点:由于每次值需要存放触发事件的位置,占用内存较少
Sax的缺点:不支持随机访问