SAX解析xml浅析
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()方法。
特别注意:
- public void endElement(String uri, String localName, String qName)
- throws SAXException {
- if("book".equals(qName)){
- books.add(book);
- book = null;
- }
- currentTag= null;/**当解析结束时置为空。这里很重要,例如遇到</book>---/book--- <book id="15">,会调用这个方法
- ,如果这里不把currentTag置为null,根据startElement(....)方法,currentTag的值还是price,因为两个标签之间有内容(---/book---),会执行characters(char[] ch, int start, int length)这个方法,而characters(....)方
- 法判断currentTag!=null,会执行if判断的代码,这样就会把空值赋值给book(因为执行了book=null,此时会有空指针异常),这不是我们想要的。*/
- }
SAX解析xml浅析的更多相关文章
- Android之SAX解析XML
一.SAX解析方法介绍 SAX(Simple API for XML)是一个解析速度快并且占用内存少的XML解析器,非常适合用于Android等移动设备. SAX解析器是一种基于事件的解析器,事件驱动 ...
- Android 使用pull,sax解析xml
pull解析xml文件 1.获得XmlpullParser类的引用 这里有两种方法 //解析器工厂 XmlPullParserFactory factory=XmlPullParserFactory. ...
- JAVA使用SAX解析XML文件
在我的另一篇文章(http://www.cnblogs.com/anivia/p/5849712.html)中,通过一个例子介绍了使用DOM来解析XML文件,那么本篇文章通过相同的XML文件介绍如何使 ...
- DOM&SAX解析XML
在上一篇随笔中分析了xml以及它的两种验证方式.我们有了xml,但是里面的内容要怎么才能得到呢?如果得不到的话,那么还是没用的,解析xml的方式主要有DOM跟SAX,其中DOM是W3C官方的解析方式, ...
- cocos2d-x 3.0 使用Sax解析xml文件(中国显示器问题解决)
今天是个好日子.我以为事情可以变得,明天是个好日子.打开门儿春风... 恩,听着歌写文档生活就是这么享受. 今天曾经的邻居大神突然在qq上赞了我一下,这让我异常激动啊.. 这还要从前前前几天说起,那会 ...
- JavaWeb学习日记----SAX解析XML
1.SAX解析XML文档的方式: 与DOM方式解析不同,DOM方式解析是根据XML的层级结构在内存中分配一个树形结构,把xml的标签,属性和文本都封装成对象.优点是可以很方便实现增删改操作.缺点是,如 ...
- 用SAX解析xml文件,java
(此文为(https://www.imooc.com/video/4482)之随笔) 1.用SAX解析xml文件大致分为三步 写了一个XML文件作为例子 (1)main方法代码如下: import j ...
- Python:使用基于事件驱动的SAX解析XML
SAX的特点: 是基于事件的 API 在一个比 DOM 低的级别上操作 为您提供比 DOM 更多的控制 几乎总是比 DOM 更有效率 但不幸的是,需要比 DOM 更多的工作 基于对象和基于事件的接口 ...
- Android SAX解析XML
本篇讲解一下SAX解析XML这种方式,首先来看一下它的基本介绍: SAX是一种以事件驱动的XML API,由它定义的事件流可以指定从解析器传到专门的处理程序的代码的XML结构,简单的讲,它是种解析速度 ...
随机推荐
- nova-compute[5410]: OSError: [Errno 13] Permission denied: '图像路径'
前几天有 openstack-Nova 创建虚拟机拨弄了一下,结果重新启动后的今天 nova boot 创建虚拟机实例有错误,创建虚拟机出状况 他们是 error 视图 openstack 服务状态 ...
- JS如何判断包括IE11在内的IE浏览器
原文:JS如何判断包括IE11在内的IE浏览器 今天碰到一个奇怪的问题,有一个页面,想指定用IE浏览器打开,在VS开发环境没有问题,但部署到服务器上,即使是用IE打开页面,还是提示"仅支持I ...
- 使用 Eclipse 的 SVN 主要插件创建项目/支/标签
原文 阅读 Mark Phippard 该博客以及<Subversion 与版本号控制>之后,我了解到 分支/标签 是 SVN 非常棒的特性之中的一个.但我在使用推荐的 "tru ...
- 准备战争“软测试”之DB基础知识
"数据库"东西这个陌生和数据,进入提高班,从第二年开始接触,的项目还是自考的学习加起来也有3遍了.这仅仅是一个開始,软考又要对数据库进行全面的分析,那么如今就让我们再一次剖析它吧! ...
- 网站静态化处理—web前端优化—下【终篇】(13)
网站静态化处理—web前端优化—下[终篇](13) 本篇继续web前端优化的讨论,开始我先讲个我所知道的一个故事,有家大型的企业顺应时代发展的潮流开始投身于互联网行业了,它们为此专门设立了一个事业部, ...
- <C++ 实现设计模式> 观察者模式
观察者模式,又称公布--订阅,mvc模式等. 通俗点讲,比方股票来说,非常多人关注一支股票,派一个人去观察股票的情况,一有变化(观察),就通知全部的预定这个消息的人. 而我们常见的mvc模式,v是指v ...
- C# 窗口间传递数据
C#两个窗口之间传递数据 1 公用变量值传递 public partial class Form1 : Form //parent form { public string name="&q ...
- Linux学习笔记——怎样在交叉编译时使用共享库
0.前言 在较为复杂的项目中会利用到交叉编译得到的共享库(*.so文件).在这样的情况下便会产生下面疑问,比如: [1]交叉编译时的共享库是否须要放置于目标板中,假设须要放置在哪个文件 ...
- JS实现全选,用于界面批量操作向后台传值时使用
function seltAll(){ var chckBoxSign = document.getElementById("ckb"); //ckb 全选/反选的选择框id va ...
- DB2建表语句
db2 => create table test (name char(8) not null primary key,depid smallint,pay bigint) DB20000I S ...