XML解析——SAX方式

作者: 扒块腹肌 | 来源:发表于2017-02-07 18:54 被阅读108次

    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解析——SAX方式

        本文链接:https://www.haomeiwen.com/subject/hanpittx.html