XML解析——SAX方式

SAX方式

  • 使用 DOM解析XML文檔時,需要讀取整個XML文檔,在內(nèi)存中構(gòu)架生成代表整個 DOM樹的Doucment對象,才能再對XML文檔進(jìn)行操作。如果 XML 文檔特別大,就會消耗計(jì)算機(jī)的大量內(nèi)存,并且容易導(dǎo)致內(nèi)存溢出。
  • SAX解析采用事件處理的方式解析XML文件,允許在讀取文檔的時候,即對文檔進(jìn)行處理,而不必等到整個文檔裝載完才會文檔進(jìn)行操作

SAX解析原理

解析器和事件處理器

  • 使用JAXP的API創(chuàng)建出SAX解析器后,可以指定解析器去解析某個XML文檔。 在解析某個XML文檔時,每解析到XML文檔的一個組成部分,都會去調(diào)用事件處理器的一個方法,該方法會把當(dāng)前解析到的XML文件內(nèi)容作為方法的參數(shù)傳遞給事件處理器
  • 事件處理器由程序員編寫,程序員通過事件處理器中方法的參數(shù),就可以很輕松地得到sax解析器解析到的數(shù)據(jù),從而可以決定如何對數(shù)據(jù)進(jìn)行處理
    SAX解析模型.png

解析流程

使用SAXParserFactory創(chuàng)建SAX解析工廠
SAXParserFactory spf = SAXParserFactory.newInstance();
通過SAX解析工廠得到解析器對象        
SAXParser sp = spf.newSAXParser();
通過解析器對象得到一個XML的讀取器
XMLReader xmlReader = sp.getXMLReader();
設(shè)置讀取器的事件處理器     
xmlReader.setContentHandler(new BookParserHandler());
解析xml文件 
xmlReader.parse("book.xml");

SAX解析編程

xml文檔:
<?xml version="1.0" encoding="utf-8"?>
 <書架>
    <書>
        <書名>浪潮之巔</書名>
        <作者>吳軍</作者>
        <售價>50</售價>
        <個人信息><age>50</age></個人信息>
    </書>
    <書>
        <書名>數(shù)學(xué)之美</書名>
        <作者 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 只用于解析數(shù)據(jù),不用于修改xml數(shù)據(jù)。
public class MySaxParserDemo
{
       public static void main(String[] args) throws Exception, SAXException
    {
        // 使用SAXParserFactory創(chuàng)建SAX解析工廠
        SAXParserFactory spf = SAXParserFactory.newInstance();
        // 通過SAX解析工廠得到解析器對象
        SAXParser sp = spf.newSAXParser();
        // 通過解析器對象得到一個XML的讀取器
        XMLReader xmlReader = sp.getXMLReader();
        // 設(shè)置讀取器的事件處理器
        xmlReader.setContentHandler(new MySaxHanlder());
        // 解析xml文件
        xmlReader.parse("book.xml");
    }
}

事件處理器
//要用sax解析xml文檔 需要自己去實(shí)現(xiàn)一個事件處理器
// 事件處理器會有一些事件的callback函數(shù),需要我們?nèi)ブ貙?
class MySaxHanlder extends DefaultHandler
{
    //用來標(biāo)識區(qū)分相同標(biāo)簽的節(jié)點(diǎn)
    boolean flag = false;
    int booknum = 0;
    //集合用來存放書對象
    ArrayList<Book> booklist = new ArrayList<>();
    Book book;
    //全局變量用來記錄每一次查找解析到的標(biāo)簽 方便清空
    String previousTagName;

    @Override
/*  startElement(String uri,String localName,String qName,Attributes attributes)
 * qName - 限定的名稱(帶有前綴),如果限定的名稱不可用,則為空字符串。
 * attributes - 元素的屬性。如果沒有屬性,則它將是空的 Attributes 對象
 * */
    // 每解析到 一個元素(element)的時候都會觸發(fā)這個函數(shù),并且將這個element的屬性attributes和值value當(dāng)作參數(shù)傳進(jìn)來
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException
    {
        // 找到第二本書的書名        
        if (qName.equals("書名")) 
        { 
            booknum++; 
            if (booknum==2) 
                { 
                    flag=true; 
                } 
        }    
        //找到了“書”開始標(biāo)簽
        if (qName.equals("書")) 
            {//創(chuàng)建對象 準(zhǔn)備接收其屬性
                book = new Book();
            }//找到“作者”標(biāo)簽
        else if (qName.equals("作者"))
        {//獲取title屬性
            String value = attributes.getValue("title");
            if (book != null)
            {//設(shè)置title
                book.setTitle(value);
            }
        }
        //本次查找完成 需要的屬性值已經(jīng)傳給對象
        previousTagName = qName;
    }

    // 當(dāng)解析到一個元素標(biāo)簽的結(jié)束的時候 會調(diào)用
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException
    {
        // System.out.println("endElement: "+qName);
        //找到了“書”結(jié)束標(biāo)簽
        if (qName.equals("書"))
        {//把書對象加入集合中 同時并將其清空 用于下一次查找
            booklist.add(book);
            book = null;
        }//本標(biāo)簽內(nèi)的查找 結(jié)束 清空tag
        previousTagName = "";
    }
    
    // 當(dāng)解析到一個文本節(jié)點(diǎn)的時候會調(diào)用
        @Override
        public void characters(char[] ch, int start, int length)
                throws SAXException
        {
            
        if (flag)
        {//找到了第二個書名節(jié)點(diǎn) 獲取其內(nèi)容
            System.out.println("文本節(jié)點(diǎn):" + new String(ch, start, length));
            flag = false;
        }

            //獲取文本節(jié)點(diǎn)內(nèi)容
            String text = new String(ch, start, length);
            switch (previousTagName)
            {//標(biāo)簽值如果匹配<書名> 把書名標(biāo)簽的文本內(nèi)容傳給book對象
                case "書名":
                    book.setName(text);
                    break;
                case "作者":
                    book.setAuthor(text);
                    break;
                case "售價":
                    book.setPrice(text);
                    break;
                case "age":
                    //標(biāo)簽匹配age  text中存的是字符串
                    book.setAge(Integer.parseInt(text));
                    break;
                default:
                    break;
            }
        }
    // 當(dāng)解析到一個document文檔的開始的時候會調(diào)用
    @Override
    public void startDocument() throws SAXException
    {
        System.out.println("startDocument:");
    }
    // 當(dāng)解析到一個document文檔的結(jié)尾的時候 會調(diào)用
    @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:
文本節(jié)點(diǎn):數(shù)學(xué)之美
endDocument:[Book [name=浪潮之巔, author=吳軍, price=50, age=50, title=null], Book [name=數(shù)學(xué)之美, author=陸奇, price=29, age=50, title=ADS]]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容