使用SAX解析文档 --《第一行代码Android》学习笔记

原创 2015年11月19日 01:11:55

一、工作流程

SAX(Simple API for XML)使用回调模型与用户代码交互,这是一种基于事件的编程模型。基于事件的编程模型的特点在于用户代码不是主动去执行,也就是说,它从来不会去指使XML解析器去做这做那,它是被动的,在等待被调用,然后才会去执行程序。

SAX由解析器用户代码组成。在处理整个文档时,解析器负责逐个依次扫描文档元素,用户代码负责侦听事件并执行响应,当解析器遇到标签、文本等元素,都会触发相应的用户代码。在SAX的解析过程中,读取到文档开头元素开头元素内容元素结尾文档结尾分别会调用:startDocument()startElement()characters()endElement()endDocument()、开发人员可以根据需要,为感兴趣的事件编写相应的处理逻辑。

这里写图片描述

(若想知道文档元素是如何触发相应事件的,也许阅读SAX源代码会有些帮助?SAX源代码下载


二、用户代码

查看Android API可知,startDocument()startElement()characters()endElement()endDocument() 这五个方法在 ContentHandler 接口中被定义,若想使用这五个方法,首先必须实现ContentHandler接口。

然而这里我们不需要直接去定义一个类去implements ContentHandler,因为Java已经帮我们做好了这个事情,DefaultHandler 类实现了ContentHandler接口并重写了上述的五个方法,但是都是空方法,”By default, do nothing. Application writers may override this method in a subclass to take specific actions”,在默认情况下,什么都不做,开发人员可以在子类中重写方法以便作出针对性的处理。

所以第一步,我们新建一个类并继承DefaultHandler,并重写父类的五个方法。

  • 《第一行代码》书中把新建的类命名为ContentHandler,注意这里的ContentHandler为自定义的类名,不是org.xml.sax.ContentHandler,为避免混淆,建议将自定义的类名命名为SaxHandler、MyHandler等其它名字

  • 如果按照书中的写法,将新建的类命名为ContentHandler,那么在MainActivity中使用ContentHandler handler = new ContentHandler();时,不可以导入包org.xml.sax.ContentHandler!否则使用的ContentHandler就不是自定义的类了

public class MyHandler extends DefaultHandler {

    @Override
    public void startDocument() throws SAXException {
        ...
    }
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) {
        ...
    }
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        ...
    }
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        ...
    }
    @Override
    public void endDocument() throws SAXException {
    }
}


三、解析器

有以下两种方法实现解析器:

1. 使用XMLReader(《第一行代码》书中方法)

SAXParserFactory factory = SAXParserFactory.newInstance();  //新建工厂类
XMLReader xmlReader = factory.newSAXParser().getXMLReader(); //通过工厂类获取SAXParser类实例,并再次获取到XMLReader实例
MyHandler myHandler = new MyHandler();
xmlReader.setContentHandler(myHandler);
xmlReader.parse(new InputSource(new StringReader(response)));

我们新建一个工厂类SAXParserFactory,让工厂类产生一个SAX的解析类SAXParser并从SAXPsrser中得到一个XMLReader实例。综上所述,SAX解析XML可以归纳为六个步骤:

  1. 新建一个工厂类SAXParserFactory
    SAXParserFactory factory =SAXParserFactory.newInstance();

  2. 让工厂类产生一个SAX的解析类SAXParser
    SAXParser parser = factory.newSAXParser();

  3. 从SAXParser中得到一个XMLReader实例
    XMLReader reader = parser.getXMLReader();

  4. 得到内容处理器
    MyHandler myHandler = new MyHandler();

  5. 把自己写的handler注册到XMLReader中
    reader.setContentHandler(myHandler);

  6. 将一个xml变成一个java可以处理的InputStream流后,解析开始
    reader.parse(newInputSource(new FileInputStream("books.xml")));
    或者把xml变成字符串,
    reader.parse(new InputSource(new StringReader(xmlString)));

2. 不使用XMLReader,直接使用SAXParser

上述的步骤1、2不变,产生SAX的解析类SAXParser后,不必获取到XMLReader类实例,查看API 可以看到SAXParser类下也有parse方法,直接使用parse方法解析,同时传入两个参数——要解析的数据和用户代码(回调的方法)

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

MyHandler myHandler = new MyHandler();
parser.parse(new InputSource(new StringReader(response)), myHandler);

以上这两种方法解析所得的结果完全一致,任选一种方法即可,似乎第一种方法使用更广泛…至于为什么要对同样的目的设计两种方法,我不清楚,但是注意到XMLReader包含在由第三方提供的包org.xml.sax.XMLReader中。

3. 使用XMLReaderFactory获取XMLReader实例(注意要设置系统属性!)

在 1 中通过工厂类SAXParserFactory获取到SAXParser再获取到XMLReader,然而还可以通过另外的工厂类XMLReaderFactory,使用静态方法createXMLReader获取。XMLReader myReader = XMLReaderFactory.createXMLReader();

然而这种方法可以通过编译,但是运行时会提示错误“Can’t create default XMLReader; is system property org.xml.sax.driver set?”。解决办法:在MainActivity类的onCreate方法中添加语句设置driver系统属性,System.setProperty("org.xml.sax.driver","org.xmlpull.v1.sax2.Driver");,通过这个语句将org.xml.sax.driver的值设定为org.xmlpull.v1.sax2.Driver即可。

XMLReader xmlReader = XMLReaderFactory.createXMLReader();

MyHandler myHandler = new MyHandler();
xmlReader.setContentHandler(myHandler);
xmlReader.parse(new InputSource(new StringReader(response)));

这样做可能的原因是:所有兼容SAX标准的XML解析器都必须实现SAX中的org.xml.sax.XMLReader接口,不同解析器提供商实现了接口的类的名字(或者包名)不同。那么实例化XMLReader时,利用不同提供商的类实例化所使用的语句也就不同。为了避免这种情况,才引入了XMLReaderFactory类,通过XMLReaderFactory.createXMLReader();方法统一了实例化的语句。但即使XMLReaderFactory类,也必须指定解析器提供商,通过设置org.xml.sax.driver属性来指定。

在写Java程序时,这个系统属性可以在运行时使用java -Dorg.xml.sax.driver=org.apache.xerces.parsers.SAXparser来指定。


四、待解决问题

解析器读取标签之后还会读取一个空白本文,即使看上去那里并没有任何内容?


参考书籍:第一行代码Android、Java与XML(第三版)Oreilly&中国电力出版社

版权声明:欢迎转载,转载请注明出处。

SAX解析XML 详解

SAX解析XML 详解
  • liuquan0071
  • liuquan0071
  • 2015年12月11日 15:28
  • 1883

QT开发(四十三)——SAX方式解析XML

QT开发(四十三)——SAX方式解析XML一、SAX简介SAX是Simple API for XML的简写,是一种解析XML文件的替代方法,不是由W3C官方所提出的标准,是一种事件驱动的XML API...
  • A642960662
  • A642960662
  • 2017年03月26日 12:47
  • 267

XML解析之SAX解析过程代码详解

上一篇谢了解析原理和过程,这里应用代码直观认识这个原理: 新建Demo1类: import java.io.File; import javax.xml.parsers.SAXParser; ...
  • qq_32059827
  • qq_32059827
  • 2016年05月31日 13:12
  • 936

java中用SAX解析XML

原文地址:http://www.cnblogs.com/allenzheng/archive/2012/12/01/2797196.html 注:考虑到自己程序中表结构比较大,有几百个字段,再加...
  • w2393040183
  • w2393040183
  • 2016年07月15日 11:11
  • 1653

Java解析xml文档之SAX解析

sax解析是一种边读边解析,仅向前读取,不能修改,用来读。sax创建XMLReader三步:SAXParserFactory factory = SAXParserFactory.newInstanc...
  • new___Smile
  • new___Smile
  • 2016年07月16日 00:59
  • 3510

使用SAX方式解析XML文件

SAX方式解析XML的步骤: 1、通过SAXParseFactory的静态newInstance()方法获取SAXParseFactory实例factory 2、SAXParseFactory实例的n...
  • u014042146
  • u014042146
  • 2015年09月15日 18:16
  • 858

android中使用SAX解析xml(封装)

SAX具体怎么用就不说了,网上搜搜一大片。 第一步:建立公共抽象类BaseHandler package com.dc.handler; import java.io.StringRead...
  • gundumw100
  • gundumw100
  • 2017年04月10日 18:08
  • 240

使用SAX方式解析XML

一、创建XML文件 目录结构: 二、新建一个带有main方法的类(SAXTest.java)public class SAXTest { public static void main(S...
  • L_in12
  • L_in12
  • 2016年07月13日 14:17
  • 4906

JavaEE实战——XML文档DOM、SAX、STAX解析方式详解

本文主要介绍XML文档作为存储和传输数据的三种解析方式,其各自主要的思想、实现方式、CURD实现,以及最后展示一个综合的实战例子加以巩固理解。...
  • zhongkelee
  • zhongkelee
  • 2016年06月22日 23:10
  • 2220

Android中三种常用解析XML的方式(DOM、SAX、PULL)简介及区别

XML在各种开发中都广泛应用,Android也不例外。作为承载数据的一个重要角色,如何读写XML成为Android开发中一项重要的技能。今天就由我向大家介绍一下在Android平台下几种常见的XML解...
  • cangchen
  • cangchen
  • 2015年03月03日 10:17
  • 3624
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用SAX解析文档 --《第一行代码Android》学习笔记
举报原因:
原因补充:

(最多只允许输入30个字)