xml解析学习笔记

  今天我总结一下我学习xml解析的一些知识。
  xml的解析方式有两种,一种是DOM,是一种基于文档驱动的解析方式。另一种是SAX,是一种基于事件的解析方式。

DOM解析

  DOM的解析过程是先将需要解析的xml文档一次性读到内存,并创建Document树。可以随机获得任何节点信息。也可以修改Document树结构,即修改xml内容。其是一种面向对象的编程思想。缺点:由于一次性将文件的所有内容全读到了内存中,因此,当文件内容比较多时,很耗内存。
  
1、 读取过程(使用dom4j工具)

xml结构:

<?xml version="1.0" encoding="utf-8"?>
<studentList>
    <student id="001">
        <name>张三</name>
        <age>20</age>
        <stature>178</stature>
    </student>
    <student id="002">
        <name>李四</name>
        <age>24</age>
        <stature>165</stature>
    </student>
</studentList>

student.java

public class Student {

    private final String id;
    private String name;
    private int age;
    private double stature;

    public Student(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }
    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 double getStature() {
        return stature;
    }
    public void setStature(double stature) {
        this.stature = stature;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(id)
                .append(" : ").append(name)
                .append(" age : ").append(age)
                .append(" stature : ").append(stature);

        return sb.toString();
    }

}
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.QName;
import org.dom4j.io.SAXReader;

public class DOMReader {

    public static void main(String[] args) throws DocumentException {

        // 获得xml文档的Document树结构
        Document doc = new SAXReader().read(new File("./src/student.xml"));
        // 获取根节点,即studentList
        Element rootElem = doc.getRootElement();
        // 获取根节点的所有子节点,即所有student节点
        // 还可以通过rootElem.elementIterator();遍历所有子节点
        List<Element> elems = rootElem.elements();
        List<Student> stuList = new ArrayList<Student>();
        for(Element elem : elems ) {
            Student stu = new Student(elem.attributeValue("id"));
            List<Element> childs = elem.elements();
            for(Element e : childs ) {
                final QName qName = e.getQName();
                String value = e.getText();
                switch( qName.getName() ) {
                case "name":
                    stu.setName(value);
                    break;
                case "age":
                    stu.setAge(Integer.valueOf(value));
                    break;
                case "stature":
                    stu.setStature(Double.valueOf(value));
                    break;
                default:
                    break;
                }
            }
            stuList.add(stu);
        }

        for(Student stu : stuList ) {
            System.out.println(stu);
        }
    }
}

  运行结果如下:
    这里写图片描述

2、修改xml内容

    // 将document对象修改过后,直接写入文件就可以了
    rootElem.setName("listStudent");

    XMLWriter writer = new XMLWriter(
                new FileOutputStream(new File("./src/student.xml")));
    writer.write(doc);
    writer.flush();
    writer.close();

3、xpath技术
  当xml文档的结构比较深时,对节点的查找非常麻烦,就可以用xpath解决这个问题,xpath依赖包不在dom4j的核心包中,因此要引入其依赖包 jaxen-1.1-beta-6.jar
  使用xpath只有两个方法:
  selectNodes(“xpath表达式”);查找符合条件的所有节点对象
  selectSingleNode(“xpath表达式”);查找符合条件的单个节点对象
4、 xpath语法

/**
  符号的含义:
    /      绝对路径      表示从xml的根位置开始,有层次结构
    //     相对路径      表示不分层次结构的选择元素
    *      通配符        表示匹配所有元素节点
    @*     通配符        表示匹配所有的属性
    node() 通配符        表示匹配任何类型的节点(比如属性)
    []     条件          表示选择符合条件的元素
    @      属性          表示选择属性节点
    |      运算符        表示表示匹配多个路径
    and    运算符        表示条件与(等价于&&)
    or     运算符        表示条件或(等价于||)
    有关函数:
    last()              表示当前节点的最后一个子元素
    text() 文本          表示选择文本内容
    count()             表示计数符合条件的节点个数
    name()              表示返回节点的名称
    starts-with(,)      表示第一个字符串以第二个字符串开始
    contains(,)         表示第一个字符串包含第二个字符串
    string-length()     表示返回字符串的长度
    normalize-space()   表示将前后空格删除,并将连续空格替换为单个空格

*/

SAX解析

  SAX解析是基于事件的解析方式。即在遍历xml文件时,只有相应的事件被触发了,才会执行回调来取得数据。因此,其解析过程是从前往后的,只能顺序读取,不能回读。优点就是内存消耗较少。
  
1. 读取过程

    // 由于SAX解析类内置在jdk中,所以不需要使用工具
    // 核心类 SAXParser
    SAXParser parser = SAXParserFactory.newInstance().newParser();
    // 调用parse方法解析xml
    // parse(File, DefaultHandler)
    parser.parse(new File("./src/test.xml"), new MyDefaultHandler());

  其主要就是自己继承解析回调的类DefaultHandler来实现解析时回调的方法。DefaultHandler实现了EntityResolver, DTDHandler, ContentHandler, ErrorHandler接口,但除了方法fatalError直接抛出异常外,其余的方法全部都是空的,没有任何操作。我们实现MyDefaultHandler类的时候,主要覆写的方法为ContentHandler接口中的startDocument, startElement, endElement, endDocument, characters。
  下面我们看看具体例子:

MyDefaultHandler.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 MyDefaultHandler extends DefaultHandler{

    private static final String attrId = "id";
    private static final String nodeAge = "age";
    private static final String nodeName = "name";
    private static final String nodeStudent = "student";
    private static final String nodeStature = "stature";
    private static final String nodeStudentList = "studentList";

    private Student stu;
    private String tag;
    private List<Student> myList;

    public List<Student> getStudents() {
        return myList;
    }

    // 在遇到<?xml version="1.0" encoding="utf-8"?>时调用该方法
    @Override
    public void startDocument() throws SAXException {
        myList = new ArrayList<Student>();
    }

    // 在每个标签开始时调用
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if( qName.equals(nodeStudent) && attributes != null ) {
            stu = new Student(attributes.getValue(attrId));
        }
        tag = qName;
    }

    // 获取每个标签的文本时调用
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        String str = new String(ch, start, length);
        if( stu != null && tag != null ) {
            str = new String(ch, start, length);
            switch( tag ) {
            case nodeName:
                stu.setName(str);
                break;
            case nodeAge:
                stu.setAge(Integer.valueOf(str));
                break;
            case nodeStature:
                stu.setStature(Double.valueOf(str));
                break;
            default:
                break;  
            }
        }
    }

    // 每个标签结束时调用
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if( qName.equals(nodeStudent) && stu != null ) {
            myList.add(stu);
            stu = null;
        }
        tag = null;
    }
}

test类:

public class SAXReader {

    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {

        SAXParser sax = SAXParserFactory.newInstance().newSAXParser();
        MyDefaultHandler handler = new MyDefaultHandler();
        sax.parse(new File("./src/student.xml"), handler);
        List<Student> stuList = handler.getStudents();
        for(Student stu : stuList ) {
            System.out.println(stu);
        }
    }

}

  运行结果如下:
  这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值