SAX解析XML文件采用事件驱动的方式进行,也就是说,SAX是逐行扫描文件,遇到符合条件的设定条件后就会触发特定的事件,回调你写好的事件处理程序。使用SAX的优势在于其解析速度较快,占用内存较少(相对于DOM而言)。而且SAX在解析文件的过程中得到自己需要的信息后可以随时终止解析,并不一定要等文件全部解析完毕。凡事有利必有弊,其劣势在于SAX采用的是流式处理方式,当遇到某个标签的时候,它并不会记录下以前所遇到的标签,也就是说,在处理某个标签的时候,比如在 startElement方法中,所能够得到的信息就是标签的名字和属性,至于标签内部的嵌套结构,上层标签、下层标签以及其兄弟节点的名称等等与其结构相关的信息都是不得而知的。实际上就是把XML文件的结构信息丢掉了,如果需要得到这些信息的话,只能你自己在程序里进行处理了。所以相对DOM而言,SAX处理XML文档没有DOM方便,SAX处理的过程相对DOM而言也比较复杂。

为了说明sax解析xml的过程,此xml文件非标准规范的xml文档

books.xml的内容:

<?xml version='1.0' encoding='UTF-8'?>
<books>---books---
<book id="12">---book---
<name>thinking in java</name>---/name---
<price>85.5</price>---/price---
</book>---/book---
<book id="15">---book2---
<name>Spring in Action</name>---/name2---
<price>39.0</price>---/price---
</book>---/book2---
</books>---/books---

Java Sax解析是按照xml文件的顺序一步一步的来解析,在解析xml文件之前,我们要先了解xml文件的节点的种类,一种是ElementNode,一种是TextNode。如上面的这段books.xml。

其中,像<books>、<book>这种节点就属于ElementNode,而thinking in java、85.5这种就属于TextNode。还有一种特殊情况:---book--- 、---/name--- 、---/book---等都是TextNode,sax是基于事件解析xml的那么遇到这些文本节点的时候也会触发characters( )方法。(这也是books.xml写成不规范的原因,方便去理解sax解析的过程)。

既然sax是基于事件解析xml文档,那么哪些xml包含什么呢?

    <?xml version='1.0' encoding='UTF-8'?>  这个代表什么?不就是文档开始部分吗, sax就把它作为一个事件 startDocument() ,你重写这个方法就行了。

    <book id="12">  遇到元素节点的开始标签要不要作为一个事件? 当然!    startElement()  ,现在你会想到结束标签呢?同样 endElement() .....

那么接下来看看这段文字:

startDocument()

当遇到文档的开头的时候,调用这个方法,可以在其中做一些预处理的工作。

endDocument()

和上面的方法相对应,当文档结束的时候,调用这个方法,可以在其中做一些善后的工作。

startElement(String uri, String localName, String qName, Attributes atts)

当读到一个开始标签的时候,会触发这个方法。uri是命名空间(通过xmlns声明),localName是不带命名空间前缀的标签名,qName是带命名空间前缀的标签名。通过atts可以得到所有的属性名和相应的值。注意,如果没有指定Namespace,则qName可能为空,当然不同的SAX实现会有所不同,比如在Android中qName为空,而J2SE中localName为空,所以想要总是得到标签名,就需要检查这两个参数的值了。

endElement(String uri, String localName, String name)

这个方法和上面的方法相对应,在遇到结束标签的时候,调用这个方法。

characters(char[] ch, int start, int length)

这个方法用来处理在XML文件中读到的内容,第一个参数为文件的字符串内容,后面两个参数是读到的字符串在这个数组中的起始位置和长度,使用new String(ch,start,length)就可以获取内容。

我们只要继承DefaultHandler 重写我们需要的方法就行了。

SaxParseHandler.java  让sax解析器遇到相应事件时做相应的事情:

package com.aib.sax;

import java.util.ArrayList;
import java.util.List; import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler; public class SaxParseHandler extends DefaultHandler { /***
* list 组装数据 Book 封装book信息的javabean currentTag
* 当前标签,在characters()方法中判断是否为我们处理文本信息所在的标签位置
*/
private List<Book> list;
private Book book; @Override
public String toString() {
return "SaxParseHandler [list=" + list + "]";
} public List<Book> getList() {
return list;
} private String currentTag; @Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// 输出ch,用于测试...
System.out.println("characters方法中currentTag=" + currentTag);
System.out.println("characters方法中解析到的文本为:" + new String(ch,start,length)+"---结束标记---"); if (currentTag != null ) {
if (currentTag.equals("name")) {
book.setBookName(new String(ch, start, length));
} else if (currentTag.equals("price")) {
book.setPrice(new String(ch, start, length));
}
} } @Override
public void startDocument() throws SAXException {
// 根据这个信息: <?xml version="1.0" encoding="UTF-8"?> 识别
System.out.println("startDocument方法中currentTag=" + currentTag);
// 已经开始读取文档,所以初始化list用于保存接下来读取的book信息。注意:此方法调用一次!
list = new ArrayList<Book>();
} @Override
public void endDocument() throws SAXException {
System.out.println("endDocument方法中currentTag=" + currentTag);
} @Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException { // 将正在解析元素节点的名称赋值给currentTag,在characters()中可以准确处理文本信息
this.currentTag = qName;
// 打印参数信息,用于测试..
System.out.println("startElement方法中currentTag=" + currentTag); if ("book".equals(qName)) {
book = new Book();
book.setId(attributes.getValue("id")); } else if ("其他你要处理的elementNode".equals(qName)) { // 本程序为了方便演示,xml文档只提取book节点的信息
} } @Override
public void endElement(String uri, String localName, String qName)
throws SAXException { if ("book".equals(qName)) {
list.add(book);
book = null; } else if ("其他节点".equals(qName)) {
//
}
System.out.println("endElement方法中currentTag=" + currentTag);
this.currentTag = null; }
}

再写一个测试类测试我们的代码:

package com.aib.sax;

import java.io.InputStream;
import java.util.List; import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory; public class Test { public static void main(String[] args) throws Exception {
// 通过工厂方式获取 SAXParser
SAXParser parse = SAXParserFactory.newInstance().newSAXParser(); // sax是基于事件解析xml ,需要程序员编写如何去处理xml文件 。
SaxParseHandler saxHandler = new SaxParseHandler();
// 通过类加载器加载xml文件,返回一个InputStream,实际应用中可以通过不同的方式加载,比如解析网络的xml文件
InputStream is = Test.class.getClassLoader().getResourceAsStream(
"books.xml");
parse.parse(is, saxHandler);
List<Book> books = saxHandler.getList();
System.out.println("\n\n");
for (Book book : books) {
System.out.println("id=" + book.getId() + "\tname="
+ book.getBookName() + "\tprice="+book.getPrice());
} } }

这是输出的结果:

 startDocument方法中currentTag=null
startElement方法中currentTag=books
characters方法中currentTag=books
characters方法中解析到的文本为:---book---
---结束标记---
startElement方法中currentTag=book
characters方法中currentTag=book
characters方法中解析到的文本为:---book---
---结束标记---
startElement方法中currentTag=name
characters方法中currentTag=name
characters方法中解析到的文本为:thinking in java---结束标记---
endElement方法中currentTag=name
characters方法中currentTag=null
characters方法中解析到的文本为:---/name---
---结束标记---
startElement方法中currentTag=price
characters方法中currentTag=price
characters方法中解析到的文本为:85.5---结束标记---
endElement方法中currentTag=price
characters方法中currentTag=null
characters方法中解析到的文本为:---/price---
---结束标记---
endElement方法中currentTag=null
characters方法中currentTag=null
characters方法中解析到的文本为:---/book---
---结束标记---
startElement方法中currentTag=book
characters方法中currentTag=book
characters方法中解析到的文本为:---book2---
---结束标记---
startElement方法中currentTag=name
characters方法中currentTag=name
characters方法中解析到的文本为:Spring in Action---结束标记---
endElement方法中currentTag=name
characters方法中currentTag=null
characters方法中解析到的文本为:---/name2---
---结束标记---
startElement方法中currentTag=price
characters方法中currentTag=price
characters方法中解析到的文本为:39.0---结束标记---
endElement方法中currentTag=price
characters方法中currentTag=null
characters方法中解析到的文本为:---/price---
---结束标记---
endElement方法中currentTag=null
characters方法中currentTag=null
characters方法中解析到的文本为:---/book2---
---结束标记---
endElement方法中currentTag=null
endDocument方法中currentTag=null id=12 name=thinking in java price=85.5
id=15 name=Spring in Action price=39.0

很清楚的看到

---books---

---/name---

---/book2---等这些内容会调用characters()方法, 说明这也是一个文本节点。

现在我们把books.xml文档修改成如下:

 <?xml version='1.0' encoding='UTF-8'?>
<books><book id="12"><name>thinking in java</name><price>85.5</price></book><book id="15"><name>Spring in Action</name><price>39.0</price></book></books>

程序运行的结果就变成了:

 startDocument方法中currentTag=null
startElement方法中currentTag=books
startElement方法中currentTag=book
startElement方法中currentTag=name
characters方法中currentTag=name
characters方法中解析到的文本为:thinking in java---结束标记---
endElement方法中currentTag=name
startElement方法中currentTag=price
characters方法中currentTag=price
characters方法中解析到的文本为:85.5---结束标记---
endElement方法中currentTag=price
endElement方法中currentTag=null
startElement方法中currentTag=book
startElement方法中currentTag=name
characters方法中currentTag=name
characters方法中解析到的文本为:Spring in Action---结束标记---
endElement方法中currentTag=name
startElement方法中currentTag=price
characters方法中currentTag=price
characters方法中解析到的文本为:39.0---结束标记---
endElement方法中currentTag=price
endElement方法中currentTag=null
endElement方法中currentTag=null
endDocument方法中currentTag=null id=12 name=thinking in java price=85.5
id=15 name=Spring in Action price=39.0

我们可以看到<books><book id="12">  两个标签之间没有内容(空格、换行符也算内容)时不会触发characters()方法。

特别注意:

  1. public void endElement(String uri, String localName, String qName)
  2. throws SAXException {
  3. if("book".equals(qName)){
  4. books.add(book);
  5. book = null;
  6. }
  7. currentTag= null;/**当解析结束时置为空。这里很重要,例如遇到</book>---/book--- <book id="15">,会调用这个方法
  8. ,如果这里不把currentTag置为null,根据startElement(....)方法,currentTag的值还是price,因为两个标签之间有内容(---/book---),会执行characters(char[] ch, int start, int length)这个方法,而characters(....)方
  9. 法判断currentTag!=null,会执行if判断的代码,这样就会把空值赋值给book(因为执行了book=null,此时会有空指针异常),这不是我们想要的。*/
  10. }

SAX解析xml浅析的更多相关文章

  1. Android之SAX解析XML

    一.SAX解析方法介绍 SAX(Simple API for XML)是一个解析速度快并且占用内存少的XML解析器,非常适合用于Android等移动设备. SAX解析器是一种基于事件的解析器,事件驱动 ...

  2. Android 使用pull,sax解析xml

    pull解析xml文件 1.获得XmlpullParser类的引用 这里有两种方法 //解析器工厂 XmlPullParserFactory factory=XmlPullParserFactory. ...

  3. JAVA使用SAX解析XML文件

    在我的另一篇文章(http://www.cnblogs.com/anivia/p/5849712.html)中,通过一个例子介绍了使用DOM来解析XML文件,那么本篇文章通过相同的XML文件介绍如何使 ...

  4. DOM&SAX解析XML

    在上一篇随笔中分析了xml以及它的两种验证方式.我们有了xml,但是里面的内容要怎么才能得到呢?如果得不到的话,那么还是没用的,解析xml的方式主要有DOM跟SAX,其中DOM是W3C官方的解析方式, ...

  5. cocos2d-x 3.0 使用Sax解析xml文件(中国显示器问题解决)

    今天是个好日子.我以为事情可以变得,明天是个好日子.打开门儿春风... 恩,听着歌写文档生活就是这么享受. 今天曾经的邻居大神突然在qq上赞了我一下,这让我异常激动啊.. 这还要从前前前几天说起,那会 ...

  6. JavaWeb学习日记----SAX解析XML

    1.SAX解析XML文档的方式: 与DOM方式解析不同,DOM方式解析是根据XML的层级结构在内存中分配一个树形结构,把xml的标签,属性和文本都封装成对象.优点是可以很方便实现增删改操作.缺点是,如 ...

  7. 用SAX解析xml文件,java

    (此文为(https://www.imooc.com/video/4482)之随笔) 1.用SAX解析xml文件大致分为三步 写了一个XML文件作为例子 (1)main方法代码如下: import j ...

  8. Python:使用基于事件驱动的SAX解析XML

    SAX的特点: 是基于事件的 API 在一个比 DOM 低的级别上操作 为您提供比 DOM 更多的控制 几乎总是比 DOM 更有效率 但不幸的是,需要比 DOM 更多的工作 基于对象和基于事件的接口 ...

  9. Android SAX解析XML

    本篇讲解一下SAX解析XML这种方式,首先来看一下它的基本介绍: SAX是一种以事件驱动的XML API,由它定义的事件流可以指定从解析器传到专门的处理程序的代码的XML结构,简单的讲,它是种解析速度 ...

随机推荐

  1. 手机新闻网站,手持移动新闻,手机报client,jQuery Mobile手机新闻网站,手机新闻网站demo,新闻阅读器开发

    我们坐在地铁.经常拿出新浪手机查看新闻.腾讯新闻,或者看新闻,等刷微信功能.你有没有想过如何实现这些目标. 移动互联网.更活泼. 由于HTML5未来,jQuery Moblie未来. 今天我用jqm的 ...

  2. oracle_oracle中修改日期的显示格式

    我的现在的日期格式是          ,要改成英文的需要输入一下命令: ALTER SESSION SET NLS_DATE_LANGUAGE=AMERICAN; 修改后变为: 同样也得若是英文要想 ...

  3. java_linux_shell_定时kill 启动java程序

    #!/bin/bash #while truedo Process_ID=`ps -ef |grep 'LoginSinaWeiboCookie.jar' |grep -v grep |awk '{p ...

  4. jquery 重复事件

    采用jquery时刻.其他活动均达到. 相反1对1的. 例如:onclick="$(document).keypress(function (key) {  if (key.keyCode ...

  5. Apache & WebDav 配置(一)

    (一)简单Apache服务器的搭建!用于文件de上传.下载.修改.删除! ---------- - Apache 1. 使用最广的 Web 服务器.支持各种脚本(PHP)的执行 2. Mac自带,只需 ...

  6. (工具)source insight高速增加时间代码

    这篇文章是程序代码更改由其他用户. 不是原厂原装,例如下列总结,使用作为个人笔记. (1)打开projectbase.打开文件Utils.em,插入下面代码: //插入时间 macro MonthTo ...

  7. BS导出csv文件的通用方法(.net)

    最近把以前项目里用的导出文件的功能提取成了dll,通过读取Attribute来得到要导出的表头(没有支持多语言),使用时只要组织好要导出的数据,调用方法就好了,希望对大家有用. 使用时只需引用下载包里 ...

  8. ASP.NET Web API和ASP.NET Web MVC中使用Ninject

    ASP.NET Web API和ASP.NET Web MVC中使用Ninject 先附上源码下载地址 一.准备工作 1.新建一个名为MvcDemo的空解决方案 2.新建一个名为MvcDemo.Web ...

  9. 【 D3.js 入门系列 --- 9.6 】 生产的包图

    我的个人博客是:www.ourd3js.com csdn博客为:blog.csdn.net/lzhlzz 转载请注明出处,谢谢. 打包图( Pack ).用于包括与被包括的关系,也表示各个对象的权重, ...

  10. UiAutomator源码分析之UiAutomatorBridge框架

    上一篇文章<UIAutomator源码分析之启动和运行>我们描述了uitautomator从命令行运行到加载测试用例运行测试的整个流程,过程中我们也描述了UiAutomatorBridge ...