XML解析——SAX方式

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]]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,571评论 18 399
  • 1. XML总结 1.1. XML简介 XML : 可扩展的标记语言。(和HTML非常类似的) 可扩展的。 自定义...
    Ethan_Walker阅读 2,983评论 0 12
  • 事件编程模式三要求: 事件源:xml文件事件:解析到开始标签(包含属性),解析到结束标签,解析文本内容监听器:De...
    小小机器人阅读 341评论 0 0
  • 新增链接http://m.blog.csdn.net/article/details?id=7305068,这一篇...
    来个芒果阅读 1,359评论 0 1
  • 一. Java基础部分.................................................
    wy_sure阅读 3,788评论 0 11