Java基礎(chǔ)之SAX解析XML

1. Java解析XML簡(jiǎn)介

Java庫(kù)中提供了兩種XML解析器:

  • 像文檔對(duì)象模型(Document Object Model,DOM)解析器這的樹型解析器(tree parse),它們將讀入的XML文檔轉(zhuǎn)換成樹結(jié)構(gòu)。
  • 像XML簡(jiǎn)單API(Simple API for XML,SAX)解析器這樣的流機(jī)制解析器(streaming parser),它們?cè)谧x入XML文檔時(shí)生成相應(yīng)的事件。

2. SAX簡(jiǎn)介

SAX解析器在解析XML輸入數(shù)據(jù)的各個(gè)組成部分時(shí)會(huì)報(bào)告事件,但不會(huì)以任何方式存儲(chǔ)文檔,而是由事件處理器建立相應(yīng)的數(shù)據(jù)結(jié)構(gòu)。實(shí)際上DOM解析器是在SAX解析器的基礎(chǔ)上構(gòu)建的,它在接收到解析器事件時(shí)構(gòu)建DOM樹。

3. 使用SAX解析器

SAX解析器架構(gòu)圖

在使用SAX解析器時(shí),需要一個(gè)處理器來為各種解析器事件定義事件動(dòng)作。DefaultHandler接口定義了若干個(gè)在解析文檔時(shí)解析器會(huì)調(diào)用的回調(diào)方法。下面是最重要的幾個(gè)方法:

  • startElement和endElement在每當(dāng)遇到起始或終止標(biāo)簽時(shí)調(diào)用。
  • characters在每當(dāng)遇到字符數(shù)據(jù)時(shí)調(diào)用。
  • startDocument和endDocument分別在文檔開始和結(jié)束時(shí)各調(diào)用一次。

例如,在解析以下片段時(shí):

<person>
    <name type="string">韓信</name>
    <age>25</age>
</person>

解析器會(huì)產(chǎn)生以下回調(diào):
1)startElement,元素名:person
2)startElement,元素名:name ,屬性:type="string"
3)characters,內(nèi)容:韓信
4)endElement,元素名:name
5)startElement,元素名:age
6)characters,內(nèi)容:25
7)endElement,元素名:age
8)endElement,元素名:person

處理器必須覆蓋這些方法,讓它們執(zhí)行在解析文件時(shí)我們想讓它們執(zhí)行的動(dòng)作。

下面通過一個(gè)簡(jiǎn)單的demo體會(huì)SAX解析XML的過程。

3.1 準(zhǔn)備xml

首先準(zhǔn)備person.xml,內(nèi)容如下

<?xml version="1.0" encoding="UTF-8" ?>
<persons>
    <person>
      <name>韓信</name>
      <age>25</age>
   </person>
   <person>
      <name>李白</name>
      <age>23</age>
   </person>
</persons>

3.2 解析代碼

  • 獲取解析工廠
  • 從解析工廠獲取解析器
  • 得到解讀器
  • 設(shè)置內(nèi)容處理器
  • 讀取xml的文檔內(nèi)容
package cn.lastwhisper.javabasic.Sax;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;

/**
 * @author lastwhisper
 * @desc SAX方式解析xml文件
 * @email gaojun56@163.com
 */
public class SaxTest {
    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        // SAX解析
        // 1.獲取解析工廠
        SAXParserFactory factory = SAXParserFactory.newInstance();
        // 2.從解析工廠獲取解析器
        SAXParser parse = factory.newSAXParser();
        // 3.得到解讀器
        XMLReader reader=parse.getXMLReader();
        // 4.設(shè)置內(nèi)容處理器
        reader.setContentHandler(new PHandler());
        // 5.讀取xml的文檔內(nèi)容
        reader.parse("src/main/java/cn/lastwhisper/javabasic/Sax/person.xml");

    }

}

class PHandler extends DefaultHandler {
    /**
     * @author lastwhisper
     * @desc 文檔解析開始時(shí)調(diào)用,該方法只會(huì)調(diào)用一次
     * @param
     * @return void
     */
    @Override
    public void startDocument() throws SAXException {
        System.out.println("----解析文檔開始----");
    }

    /**
     * @author lastwhisper
     * @desc 每當(dāng)遇到起始標(biāo)簽時(shí)調(diào)用
     * @param uri xml文檔的命名空間
     * @param localName 標(biāo)簽的名字
     * @param qName 帶命名空間的標(biāo)簽的名字
     * @param attributes 標(biāo)簽的屬性集
     * @return void
     */
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        System.out.println("標(biāo)簽<"+qName + ">解析開始");
    }

    /**
     * @author lastwhisper
     * @desc 解析標(biāo)簽內(nèi)的內(nèi)容的時(shí)候調(diào)用
     * @param ch 當(dāng)前讀取到的TextNode(文本節(jié)點(diǎn))的字節(jié)數(shù)組
     * @param start 字節(jié)開始的位置,為0則讀取全部
     * @param length 當(dāng)前TextNode的長(zhǎng)度
     * @return void
     */
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        String contents = new String(ch, start, length).trim();
        if (contents.length() > 0) {
            System.out.println("內(nèi)容為-->" + contents);
        } else {
            System.out.println("內(nèi)容為-->" + "空");
        }
    }
    /**
     * @author lastwhisper
     * @desc 每當(dāng)遇到結(jié)束標(biāo)簽時(shí)調(diào)用
     * @param uri xml文檔的命名空間
     * @param localName 標(biāo)簽的名字
     * @param qName 帶命名空間的標(biāo)簽的名字
     * @return void
     */
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        System.out.println("標(biāo)簽</"+qName + ">解析結(jié)束");
    }
    /**
     * @author lastwhisper
     * @desc 文檔解析結(jié)束后調(diào)用,該方法只會(huì)調(diào)用一次
     * @param
     * @return void
     */
    @Override
    public void endDocument() throws SAXException {
        System.out.println("----解析文檔結(jié)束----");
    }
}

運(yùn)行main函數(shù),查看運(yùn)行結(jié)果

運(yùn)行結(jié)果

3.3 分析解析過程

----解析文檔開始---- 調(diào)用startDocument
標(biāo)簽<persons>解析開始 調(diào)用startElement
內(nèi)容為-->空 調(diào)用characters,因?yàn)?lt;persons></persons>之間只有標(biāo)簽沒有內(nèi)容,所以為空。
標(biāo)簽<person>解析開始 調(diào)用startElement
內(nèi)容為-->空 調(diào)用characters,因?yàn)?lt;person></person>之間只有標(biāo)簽沒有內(nèi)容,所以為空。
標(biāo)簽<name>解析開始 調(diào)用startElement
內(nèi)容為-->韓信 調(diào)用characters,<name>韓信</name>之間內(nèi)容為:韓信
標(biāo)簽</name>解析結(jié)束 調(diào)用endElement
內(nèi)容為-->空 調(diào)用characters,每次執(zhí)行完調(diào)用endElement之后會(huì)調(diào)用一次characters
標(biāo)簽<age>解析開始 調(diào)用startElement
內(nèi)容為-->25 調(diào)用characters,<age>25</age>之間內(nèi)容為:25
標(biāo)簽</age>解析結(jié)束 調(diào)用endElement
內(nèi)容為-->空 調(diào)用characters,每次執(zhí)行完調(diào)用endElement之后會(huì)調(diào)用一次characters
標(biāo)簽</person>解析結(jié)束 調(diào)用endElement
內(nèi)容為-->空 調(diào)用characters,每次執(zhí)行完調(diào)用endElement之后會(huì)調(diào)用一次characters
...
標(biāo)簽<person>解析開始
內(nèi)容為-->空
標(biāo)簽<name>解析開始
內(nèi)容為-->李白
標(biāo)簽</name>解析結(jié)束
內(nèi)容為-->空
標(biāo)簽<age>解析開始
內(nèi)容為-->23
標(biāo)簽</age>解析結(jié)束
內(nèi)容為-->空
標(biāo)簽</person>解析結(jié)束
內(nèi)容為-->空
標(biāo)簽</persons>解析結(jié)束
----解析文檔結(jié)束---- 調(diào)用endDocument,xml解析結(jié)束

4. 解析xml到pojo對(duì)象

待解析的xml,person.xml

<?xml version="1.0" encoding="UTF-8" ?>
<persons>
    <person>
      <name>韓信</name>
      <age>25</age>
   </person>
   <person>
      <name>李白</name>
      <age>23</age>
   </person>
</persons>

xml轉(zhuǎn)換為pojo的代碼

package cn.lastwhisper.javabasic.Sax;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author lastwhisper
 * @desc 將xml數(shù)據(jù)解析到pojo中
 *
 * @email gaojun56@163.com
 */
public class SaxXmlToPojo {
    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        // SAX解析
        // 1.獲取解析工廠
        SAXParserFactory factory = SAXParserFactory.newInstance();
        // 2.從解析工廠獲取解析器
        SAXParser parse = factory.newSAXParser();
        // 3.得到解讀器
        XMLReader reader = parse.getXMLReader();
        // 4.設(shè)置內(nèi)容處理器
        PersonHandler personHandler = new PersonHandler();
        reader.setContentHandler(personHandler);
        // 5.讀取xml的文檔內(nèi)容
        reader.parse("src/main/java/cn/lastwhisper/javabasic/Sax/person.xml");

        List<Person> persons = personHandler.getPersons();
        for (Person person : persons) {
            System.out.println("姓名:" + person.getName() + " 年齡:" + person.getAge());
        }
    }

}

class PersonHandler extends DefaultHandler {
    private List<Person> persons;
    private Person person;
    private String tag; // 存儲(chǔ)操作標(biāo)簽

    /**
     * @author lastwhisper
     * @desc 文檔解析開始時(shí)調(diào)用,該方法只會(huì)調(diào)用一次
     * @param
     * @return void
     */
    @Override
    public void startDocument() throws SAXException {
        persons = new ArrayList<Person>();
    }

    /**
     * @author lastwhisper
     * @desc 標(biāo)簽(節(jié)點(diǎn))解析開始時(shí)調(diào)用
     * @param uri xml文檔的命名空間
     * @param localName 標(biāo)簽的名字
     * @param qName 帶命名空間的標(biāo)簽的名字
     * @param attributes 標(biāo)簽的屬性集
     * @return void
     */
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        tag = qName;
        if ("person".equals(tag)) {
            person = new Person();
        }
    }

    /**
     * @author lastwhisper
     * @desc 解析標(biāo)簽的內(nèi)容的時(shí)候調(diào)用
     * @param ch  字符
     * @param start 字符數(shù)組中的起始位置
     * @param length 要從字符數(shù)組使用的字符數(shù)
     * @return void
     */
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        String contents = new String(ch, start, length).trim();
        if ("name".equals(tag)) {
            person.setName(contents);
        } else if ("age".equals(tag)) {
            if (contents.length() > 0) {
                person.setAge(Integer.valueOf(contents));
            }
        }
    }

    /**
     * @author lastwhisper
     * @desc 標(biāo)簽(節(jié)點(diǎn))解析結(jié)束后調(diào)用
     * @param uri xml文檔的命名空間
     * @param localName 標(biāo)簽的名字
     * @param qName 帶命名空間的標(biāo)簽的名字
     * @return void
     */
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if ("person".equals(qName)) {
            persons.add(person);
        }
        tag = null; //tag丟棄了
    }

    /**
     * @author lastwhisper
     * @desc 文檔解析結(jié)束后調(diào)用,該方法只會(huì)調(diào)用一次
     * @param
     * @return void
     */
    @Override
    public void endDocument() throws SAXException {
    }

    public List<Person> getPersons() {
        return persons;
    }
}

運(yùn)行結(jié)果:

運(yùn)行結(jié)果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 1 XML解析No29 【 XML:可拓展標(biāo)記語(yǔ)言,語(yǔ)言和HTML類似,也是一種標(biāo)記語(yǔ)言。 特點(diǎn):標(biāo)記是自定義...
    征程_Journey閱讀 1,790評(píng)論 0 9
  • 1. XML總結(jié) 1.1. XML簡(jiǎn)介 XML : 可擴(kuò)展的標(biāo)記語(yǔ)言。(和HTML非常類似的) 可擴(kuò)展的。 自定義...
    Ethan_Walker閱讀 3,376評(píng)論 0 12
  • 什么是XML? XML 指可擴(kuò)展標(biāo)記語(yǔ)言(eXtensible Markup Language)。 你可以通過本站...
    Canon_2020閱讀 860評(píng)論 0 0
  • 一、緒論 上周工作需要了解項(xiàng)目的一些大體內(nèi)容,結(jié)果在xml解析這一塊看的迷迷糊糊的,所以在這里把學(xué)習(xí)到xm...
    cao健強(qiáng)閱讀 4,540評(píng)論 1 7
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 4,011評(píng)論 0 11

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