美文网首页Android 图片压缩
Java基础之SAX解析XML

Java基础之SAX解析XML

作者: 最后的轻语_dd43 | 来源:发表于2019-05-17 19:37 被阅读0次

    1. Java解析XML简介

    Java库中提供了两种XML解析器:

    • 像文档对象模型(Document Object Model,DOM)解析器这的树型解析器(tree parse),它们将读入的XML文档转换成树结构。
    • 像XML简单API(Simple API for XML,SAX)解析器这样的流机制解析器(streaming parser),它们在读入XML文档时生成相应的事件。

    2. SAX简介

    SAX解析器在解析XML输入数据的各个组成部分时会报告事件,但不会以任何方式存储文档,而是由事件处理器建立相应的数据结构。实际上DOM解析器是在SAX解析器的基础上构建的,它在接收到解析器事件时构建DOM树。

    3. 使用SAX解析器

    SAX解析器架构图

    在使用SAX解析器时,需要一个处理器来为各种解析器事件定义事件动作。DefaultHandler接口定义了若干个在解析文档时解析器会调用的回调方法。下面是最重要的几个方法:

    • startElement和endElement在每当遇到起始或终止标签时调用。
    • characters在每当遇到字符数据时调用。
    • startDocument和endDocument分别在文档开始和结束时各调用一次。

    例如,在解析以下片段时:

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

    解析器会产生以下回调:
    1)startElement,元素名:person
    2)startElement,元素名:name ,属性:type="string"
    3)characters,内容:韩信
    4)endElement,元素名:name
    5)startElement,元素名:age
    6)characters,内容:25
    7)endElement,元素名:age
    8)endElement,元素名:person

    处理器必须覆盖这些方法,让它们执行在解析文件时我们想让它们执行的动作。

    下面通过一个简单的demo体会SAX解析XML的过程。

    3.1 准备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>
    

    3.2 解析代码

    • 获取解析工厂
    • 从解析工厂获取解析器
    • 得到解读器
    • 设置内容处理器
    • 读取xml的文档内容
    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.设置内容处理器
            reader.setContentHandler(new PHandler());
            // 5.读取xml的文档内容
            reader.parse("src/main/java/cn/lastwhisper/javabasic/Sax/person.xml");
    
        }
    
    }
    
    class PHandler extends DefaultHandler {
        /**
         * @author lastwhisper
         * @desc 文档解析开始时调用,该方法只会调用一次
         * @param
         * @return void
         */
        @Override
        public void startDocument() throws SAXException {
            System.out.println("----解析文档开始----");
        }
    
        /**
         * @author lastwhisper
         * @desc 每当遇到起始标签时调用
         * @param uri xml文档的命名空间
         * @param localName 标签的名字
         * @param qName 带命名空间的标签的名字
         * @param attributes 标签的属性集
         * @return void
         */
        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            System.out.println("标签<"+qName + ">解析开始");
        }
    
        /**
         * @author lastwhisper
         * @desc 解析标签内的内容的时候调用
         * @param ch 当前读取到的TextNode(文本节点)的字节数组
         * @param start 字节开始的位置,为0则读取全部
         * @param length 当前TextNode的长度
         * @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("内容为-->" + contents);
            } else {
                System.out.println("内容为-->" + "空");
            }
        }
        /**
         * @author lastwhisper
         * @desc 每当遇到结束标签时调用
         * @param uri xml文档的命名空间
         * @param localName 标签的名字
         * @param qName 带命名空间的标签的名字
         * @return void
         */
        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            System.out.println("标签</"+qName + ">解析结束");
        }
        /**
         * @author lastwhisper
         * @desc 文档解析结束后调用,该方法只会调用一次
         * @param
         * @return void
         */
        @Override
        public void endDocument() throws SAXException {
            System.out.println("----解析文档结束----");
        }
    }
    

    运行main函数,查看运行结果

    运行结果

    3.3 分析解析过程

    ----解析文档开始---- 调用startDocument
    标签<persons>解析开始 调用startElement
    内容为-->空 调用characters,因为<persons></persons>之间只有标签没有内容,所以为空。
    标签<person>解析开始 调用startElement
    内容为-->空 调用characters,因为<person></person>之间只有标签没有内容,所以为空。
    标签<name>解析开始 调用startElement
    内容为-->韩信 调用characters,<name>韩信</name>之间内容为:韩信
    标签</name>解析结束 调用endElement
    内容为-->空 调用characters,每次执行完调用endElement之后会调用一次characters
    标签<age>解析开始 调用startElement
    内容为-->25 调用characters,<age>25</age>之间内容为:25
    标签</age>解析结束 调用endElement
    内容为-->空 调用characters,每次执行完调用endElement之后会调用一次characters
    标签</person>解析结束 调用endElement
    内容为-->空 调用characters,每次执行完调用endElement之后会调用一次characters
    ...
    标签<person>解析开始
    内容为-->空
    标签<name>解析开始
    内容为-->李白
    标签</name>解析结束
    内容为-->空
    标签<age>解析开始
    内容为-->23
    标签</age>解析结束
    内容为-->空
    标签</person>解析结束
    内容为-->空
    标签</persons>解析结束
    ----解析文档结束---- 调用endDocument,xml解析结束

    4. 解析xml到pojo对象

    待解析的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转换为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数据解析到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.设置内容处理器
            PersonHandler personHandler = new PersonHandler();
            reader.setContentHandler(personHandler);
            // 5.读取xml的文档内容
            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; // 存储操作标签
    
        /**
         * @author lastwhisper
         * @desc 文档解析开始时调用,该方法只会调用一次
         * @param
         * @return void
         */
        @Override
        public void startDocument() throws SAXException {
            persons = new ArrayList<Person>();
        }
    
        /**
         * @author lastwhisper
         * @desc 标签(节点)解析开始时调用
         * @param uri xml文档的命名空间
         * @param localName 标签的名字
         * @param qName 带命名空间的标签的名字
         * @param attributes 标签的属性集
         * @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 解析标签的内容的时候调用
         * @param ch  字符
         * @param start 字符数组中的起始位置
         * @param length 要从字符数组使用的字符数
         * @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 标签(节点)解析结束后调用
         * @param uri xml文档的命名空间
         * @param localName 标签的名字
         * @param qName 带命名空间的标签的名字
         * @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 文档解析结束后调用,该方法只会调用一次
         * @param
         * @return void
         */
        @Override
        public void endDocument() throws SAXException {
        }
    
        public List<Person> getPersons() {
            return persons;
        }
    }
    

    运行结果:

    运行结果

    相关文章

      网友评论

        本文标题:Java基础之SAX解析XML

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