zoukankan      html  css  js  c++  java
  • Java高级特性 第14节 解析XML文档(2)

    一、SAX解析XML文档

      SAX的全称是Simple APIs for XML,也即XML简单应用程序接口。与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式。当使用SAX分析器对XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问,因而SAX接口也被称作事件驱动接口

      1. SAX解析原理

      加载一点,读取一点,处理一点。对内存要求比较低。 

      SAX解析工具内置在jdk中:org.xml.sax.*

      

      2. SAX解析工具核心:
      核心的API:

    • SAXParser类: 用于读取和解析xml文件对象
    • parse(File f, DefaultHandler dh)方法: 解析xml文件
      • 参数一: File:表示 读取的xml文件
      • 参数二: DefaultHandler: SAX事件处理程序。使用DefaultHandler的子类

      3. 解析步骤: 

    • 第一步:创建对象

      1)创建SAXParser对象

    SAXParser parser = SAXParserFactory.newInstance().newSAXParser();

      2)调用parse方法

    /**
     * 参数一: xml文档
     * 参数二: DefaultHandler的子类 MyDefaultHandler()为自定义
     */
    parser.parse(new File(".\src\Go\person.xml"), new MyDefaultHandler());

      注意: 这里创建SAXParser对象 不能直接通过构造函数来创造,因为用到了单例工厂模式。

      DefaultHandler类的API:后三个最重要

      • void startDocument() :    在读到文档开始时调用void endDocument() :在读到文档结束时调用
      • void startElement(String uri, String localName, String qName, Attributes attributes) : 读到开始标签时调用
      • void endElement(String uri, String localName, String qName) :读到结束标签时调用
      • void characters(char[] ch, int start, int length) :  读到文本内容时调用
    • 第二步:自定义类继承DefaultHandler重写方法

      这些都是要重写的,举个例子:

    public class MyDefaultHandler extends DefaultHandler {
    
      /**
      * 开始文档时调用
      */
      @Override
      public void startDocument() throws SAXException {
        System.out.println("MyDefaultHandler.startDocument()");
      }
    
      /**
      * 开始标签时调用
      * @param qName: 表示开始标签的标签名
      * @param attributes: 表示开始标签内包含的属性列表
      */
      @Override
      public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {
        System.out.println("MyDefaultHandler.startElement()-->"+qName);
      }
    
      /**
      * 结束标签时调用
      * @param qName: 结束标签的标签名称
      */
      @Override
      public void endElement(String uri, String localName, String qName) throws SAXException {
        System.out.println("MyDefaultHandler.endElement()-->"+qName);
      }
    
      /**
      * 读到文本内容的时调用
      * @param ch: 表示当前读完的所有文本内容
      * @param start: 表示当前文本内容的开始位置
      * @param length: 表示当前文本内容的长度
      * char[]( 张三 20) 100
      * 98 2 
      */ 
      @Override
      public void characters(char[] ch, int start, int length) throws SAXException {
        //得到当前文本内容
        String content = new String(ch,start,length);
        System.out.println("MyDefaultHandler.characters()-->"+content);
      }
    
      /**
      * 结束文档时调用
      */
      @Override
      public void endDocument() throws SAXException {
        System.out.println("MyDefaultHandler.endDocument()");
      }
    }

      xml文件: 

    <?xml version="1.0" encoding="utf-8"?>
    <contactList>
      <contact id="001" name="eric">
        <name>张三</name>
        <age>20</age>
        <phone>134222223333</phone>
        <email>zhangsan@qq.com</email>
        <qq>432221111</qq>
      </contact>
      <contact id="002" name="jacky">
        <name>eric</name>
        <age>20</age>
        <phone>134222225555</phone>
        <email>lisi@qq.com</email>
        <qq>432222222</qq>
      </contact>
    </contactList>

      结果:

    MyDefaultHandler.startDocument()
    MyDefaultHandler.startElement()-->contactList
    MyDefaultHandler.characters()-->
    
    MyDefaultHandler.startElement()-->contact
    MyDefaultHandler.characters()-->
    
    MyDefaultHandler.startElement()-->name
    MyDefaultHandler.characters()-->张三
    MyDefaultHandler.endElement()-->name
    MyDefaultHandler.characters()-->
    
    MyDefaultHandler.startElement()-->age
    MyDefaultHandler.characters()-->20
    MyDefaultHandler.endElement()-->age
    MyDefaultHandler.characters()-->
    
    MyDefaultHandler.startElement()-->phone
    MyDefaultHandler.characters()-->134222223333
    MyDefaultHandler.endElement()-->phone
    MyDefaultHandler.characters()-->
    
    MyDefaultHandler.startElement()-->email
    MyDefaultHandler.characters()-->zhangsan@qq.com
    MyDefaultHandler.endElement()-->email
    MyDefaultHandler.characters()-->
    
    MyDefaultHandler.startElement()-->qq
    MyDefaultHandler.characters()-->432221111
    MyDefaultHandler.endElement()-->qq
    MyDefaultHandler.characters()-->
    
    MyDefaultHandler.endElement()-->contact
    MyDefaultHandler.characters()-->
    
    MyDefaultHandler.startElement()-->contact
    MyDefaultHandler.characters()-->
    
    MyDefaultHandler.startElement()-->name
    MyDefaultHandler.characters()-->eric
    MyDefaultHandler.endElement()-->name
    MyDefaultHandler.characters()-->
    
    MyDefaultHandler.startElement()-->age
    MyDefaultHandler.characters()-->20
    MyDefaultHandler.endElement()-->age
    MyDefaultHandler.characters()-->
    
    MyDefaultHandler.startElement()-->phone
    MyDefaultHandler.characters()-->134222225555
    MyDefaultHandler.endElement()-->phone
    MyDefaultHandler.characters()-->
    
    MyDefaultHandler.startElement()-->email
    MyDefaultHandler.characters()-->lisi@qq.com
    MyDefaultHandler.endElement()-->email
    MyDefaultHandler.characters()-->
    
    MyDefaultHandler.startElement()-->qq
    MyDefaultHandler.characters()-->432222222
    MyDefaultHandler.endElement()-->qq
    MyDefaultHandler.characters()-->
    
    MyDefaultHandler.endElement()-->contact
    MyDefaultHandler.characters()-->
    
    MyDefaultHandler.endElement()-->contactList
    MyDefaultHandler.endDocument()

      注意:结果中出现MyDefaultHandler.characters()–>空白 ,是因为<contactList>   <contact>之间也是有文本的,是换行和空格被characters方法读取了。

     二、DOM解析和SAX解析总结

    DOM解析  SAX解析 
    原理: 一次性加载xml文档,不适合大容量的文件读取 原理: 加载一点,读取一点,处理一点。适合大容量文件的读取
    DOM解析可以任意进行增删改成 SAX解析只能读
    DOM解析任意读取任何位置的数据,甚至往回读 取SAX解析只能从上往下,按顺序读取,不能往回读
    DOM解析面向对象的编程方法(Node,Element,Attribute),Java开发者编码比较简单。 SAX解析基于事件的编程方法。java开发编码相对复杂

    三、使用SAX读取XML数据实例

      books.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <bookstore>
        <book id="1">
            <name>冰与火之歌</name>
            <author>乔治马丁</author>
            <year>2014</year>
            <price>89</price>
        </book>
        <book id="2">
            <name>安徒生童话</name>
            <year>2004</year>
            <price>77</price>
            <language>English</language>
        </book>    
    </bookstore>

      SAXParserHandler.java: 

    public class SAXParserHandler extends DefaultHandler {
        String value = null;
        Book book = null;
        private ArrayList<Book> bookList = new ArrayList<Book>();
        public ArrayList<Book> getBookList() {
            return bookList;
        }
    
        int bookIndex = 0;
        /**
         * 用来标识解析开始
         */
        @Override
        public void startDocument() throws SAXException {
            // TODO Auto-generated method stub
            super.startDocument();
            System.out.println("SAX解析开始");
        }
        
        /**
         * 用来标识解析结束
         */
        @Override
        public void endDocument() throws SAXException {
            // TODO Auto-generated method stub
            super.endDocument();
            System.out.println("SAX解析结束");
        }
        
        /**
         * 解析xml元素
         */
        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            //调用DefaultHandler类的startElement方法
            super.startElement(uri, localName, qName, attributes);
            if (qName.equals("book")) {
                bookIndex++;
                //创建一个book对象
                book = new Book();
                //开始解析book元素的属性
                System.out.println("======================开始遍历某一本书的内容=================");
                //不知道book元素下属性的名称以及个数,如何获取属性名以及属性值
                int num = attributes.getLength();
                for(int i = 0; i < num; i++){
                    System.out.print("book元素的第" + (i + 1) +  "个属性名是:" + attributes.getQName(i));
                    System.out.println("---属性值是:" + attributes.getValue(i));
                    if (attributes.getQName(i).equals("id")) {
                        book.setId(attributes.getValue(i));
                    }
                }
            }
            else if (!qName.equals("name") && !qName.equals("bookstore")) {
                System.out.print("节点名是:" + qName + "---");
            }
        }
        
        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            //调用DefaultHandler类的endElement方法
            super.endElement(uri, localName, qName);
            //判断是否针对一本书已经遍历结束
            if (qName.equals("book")) {
                bookList.add(book);
                book = null;
                System.out.println("======================结束遍历某一本书的内容=================");
            }
            else if (qName.equals("name")) {
                book.setName(value);
            }
            else if (qName.equals("author")) {
                book.setAuthor(value);
            }
            else if (qName.equals("year")) {
                book.setYear(value);
            }
            else if (qName.equals("price")) {
                book.setPrice(value);
            }
            else if (qName.equals("language")) {
                book.setLanguage(value);
            }
        }
        
        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            // TODO Auto-generated method stub
            super.characters(ch, start, length);
            value = new String(ch, start, length);
            if (!value.trim().equals("")) {
                System.out.println("节点值是:" + value);
            }
        }
    }

      SAXTest.java:

    public class SAXTest {
        /**
         * @param args
         */
        public static void main(String[] args) {
            //锟斤拷取一锟斤拷SAXParserFactory锟斤拷实锟斤拷
            SAXParserFactory factory = SAXParserFactory.newInstance();
            //通锟斤拷factory锟斤拷取SAXParser实锟斤拷
            try {
                SAXParser parser = factory.newSAXParser();
                //锟斤拷锟斤拷SAXParserHandler锟斤拷锟斤拷
                SAXParserHandler handler = new SAXParserHandler();
                parser.parse("books.xml", handler);
                System.out.println("~!~!~!共有" + handler.getBookList().size() + "本书");
                for (Book book : handler.getBookList()) {
                    System.out.println(book.getId());
                    System.out.println(book.getName());
                    System.out.println(book.getAuthor());
                    System.out.println(book.getYear());
                    System.out.println(book.getPrice());
                    System.out.println(book.getLanguage());
                    System.out.println("----finish----");
                }
            } catch (ParserConfigurationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (SAXException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

      

  • 相关阅读:
    通过mixins方法处理调取服务器时间
    记录个人对vuex的简单理解
    利用弹性布局实现垂直居中
    vue.set的适用方法
    深拷贝和浅拷贝的实现方法
    Maven安装步骤
    build tools
    Git
    Url和Uri的区别
    函数式编程语言
  • 原文地址:https://www.cnblogs.com/yutianbao/p/10779709.html
Copyright © 2011-2022 走看看