×
广告

XML解析——SAX方式

96
扒块腹肌
2017.02.07 18:54* 字数 364

SAX方式

  • 使用 DOM解析XML文档时,需要读取整个XML文档,在内存中构架生成代表整个 DOM树的Doucment对象,才能再对XML文档进行操作。如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。
  • SAX解析采用事件处理的方式解析XML文件,允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作

SAX解析原理

解析器和事件处理器

  • 使用JAXP的API创建出SAX解析器后,可以指定解析器去解析某个XML文档。 在解析某个XML文档时,每解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,该方法会把当前解析到的XML文件内容作为方法的参数传递给事件处理器
  • 事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理
    SAX解析模型.png

解析流程

使用SAXParserFactory创建SAX解析工厂
SAXParserFactory spf = SAXParserFactory.newInstance();
通过SAX解析工厂得到解析器对象        
SAXParser sp = spf.newSAXParser();
通过解析器对象得到一个XML的读取器
XMLReader xmlReader = sp.getXMLReader();
设置读取器的事件处理器     
xmlReader.setContentHandler(new BookParserHandler());
解析xml文件 
xmlReader.parse("book.xml");

SAX解析编程

xml文档:
<?xml version="1.0" encoding="utf-8"?>
 <书架>
    <书>
        <书名>浪潮之巅</书名>
        <作者>吴军</作者>
        <售价>50</售价>
        <个人信息><age>50</age></个人信息>
    </书>
    <书>
        <书名>数学之美</书名>
        <作者 title='ADS'>陆奇</作者>
        <售价>29</售价>
        <个人信息><age>50</age></个人信息>
    </书>
</书架>
SAX解析代码
import java.util.ArrayList;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

// sax 只用于解析数据,不用于修改xml数据。
public class MySaxParserDemo
{
       public static void main(String[] args) throws Exception, SAXException
    {
        // 使用SAXParserFactory创建SAX解析工厂
        SAXParserFactory spf = SAXParserFactory.newInstance();
        // 通过SAX解析工厂得到解析器对象
        SAXParser sp = spf.newSAXParser();
        // 通过解析器对象得到一个XML的读取器
        XMLReader xmlReader = sp.getXMLReader();
        // 设置读取器的事件处理器
        xmlReader.setContentHandler(new MySaxHanlder());
        // 解析xml文件
        xmlReader.parse("book.xml");
    }
}

事件处理器
//要用sax解析xml文档 需要自己去实现一个事件处理器
// 事件处理器会有一些事件的callback函数,需要我们去重写

class MySaxHanlder extends DefaultHandler
{
    //用来标识区分相同标签的节点
    boolean flag = false;
    int booknum = 0;
    //集合用来存放书对象
    ArrayList<Book> booklist = new ArrayList<>();
    Book book;
    //全局变量用来记录每一次查找解析到的标签 方便清空
    String previousTagName;

    @Override
/*  startElement(String uri,String localName,String qName,Attributes attributes)
 * qName - 限定的名称(带有前缀),如果限定的名称不可用,则为空字符串。
 * attributes - 元素的属性。如果没有属性,则它将是空的 Attributes 对象
 * */
    // 每解析到 一个元素(element)的时候都会触发这个函数,并且将这个element的属性attributes和值value当作参数传进来
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException
    {
        // 找到第二本书的书名        
        if (qName.equals("书名")) 
        { 
            booknum++; 
            if (booknum==2) 
                { 
                    flag=true; 
                } 
        }    
        //找到了“书”开始标签
        if (qName.equals("书")) 
            {//创建对象 准备接收其属性
                book = new Book();
            }//找到“作者”标签
        else if (qName.equals("作者"))
        {//获取title属性
            String value = attributes.getValue("title");
            if (book != null)
            {//设置title
                book.setTitle(value);
            }
        }
        //本次查找完成 需要的属性值已经传给对象
        previousTagName = qName;
    }

    // 当解析到一个元素标签的结束的时候 会调用
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException
    {
        // System.out.println("endElement: "+qName);
        //找到了“书”结束标签
        if (qName.equals("书"))
        {//把书对象加入集合中 同时并将其清空 用于下一次查找
            booklist.add(book);
            book = null;
        }//本标签内的查找 结束 清空tag
        previousTagName = "";
    }
    
    // 当解析到一个文本节点的时候会调用
        @Override
        public void characters(char[] ch, int start, int length)
                throws SAXException
        {
            
        if (flag)
        {//找到了第二个书名节点 获取其内容
            System.out.println("文本节点:" + new String(ch, start, length));
            flag = false;
        }

            //获取文本节点内容
            String text = new String(ch, start, length);
            switch (previousTagName)
            {//标签值如果匹配<书名> 把书名标签的文本内容传给book对象
                case "书名":
                    book.setName(text);
                    break;
                case "作者":
                    book.setAuthor(text);
                    break;
                case "售价":
                    book.setPrice(text);
                    break;
                case "age":
                    //标签匹配age  text中存的是字符串
                    book.setAge(Integer.parseInt(text));
                    break;
                default:
                    break;
            }
        }
    // 当解析到一个document文档的开始的时候会调用
    @Override
    public void startDocument() throws SAXException
    {
        System.out.println("startDocument:");
    }
    // 当解析到一个document文档的结尾的时候 会调用
    @Override
    public void endDocument() throws SAXException
    {
        System.out.println("endDocument:" + booklist);
    }   
}
BOOK类
package com.cskaoyan.saxparser;

public class Book
{

    String name;
    String author;
    String price;
    int age;
    String title;

    public Book(String name, String author, String price, int age, String title)
    {
        super();
        this.name = name;
        this.author = author;
        this.price = price;
        this.age = age;
        this.title = title;
    }

    public Book()
    {
        super();
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public String getAuthor()
    {
        return author;
    }

    public void setAuthor(String author)
    {
        this.author = author;
    }

    public String getPrice()
    {
        return price;
    }

    public void setPrice(String price)
    {
        this.price = price;
    }

    public int getAge()
    {
        return age;
    }

    public void setAge(int age)
    {
        this.age = age;
    }

    public String getTitle()
    {
        return title;
    }

    public void setTitle(String title)
    {
        this.title = title;
    }

    @Override
    public String toString()
    {
        return "Book [name=" + name + ", author=" + author + ", price=" + price
                + ", age=" + age + ", title=" + title + "]";
    }

}

控制台输出集合:
startDocument:
文本节点:数学之美
endDocument:[Book [name=浪潮之巅, author=吴军, price=50, age=50, title=null], Book [name=数学之美, author=陆奇, price=29, age=50, title=ADS]]
XMl
Web note ad 1