`
and4walker
  • 浏览: 557849 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

SAX

    博客分类:
  • XML
阅读更多
SAX(Simple API for XML)由XML-DEV邮件列表成员开发,目前版本2.0.x,民间标准.http://www.saxproject.org/
SAX是一种基于事件驱动的API。利用SAX解析XML文档牵涉到两个部分:解析器和事件处理器。
解析器负责读取XML文档,并向事件处理器发送事件,如元素开始跟元素结束事件;而事件处理器则负责对事件作出相应,对传递的XML数据进行处理。

SAX特点:操作XML时不同全部读取到内存中。

SAX的处理机制:
<?xml version="1.0" encoding="gb2312"?>
<student>
   <name>张三</name>
</student>

文档开始
  元素开始(<student>)
    字符空白(">"到"<"之间的空白)
       元素开始(<name>)
          字符数据(张三)
       元素结束(</name>)
    字符空白(">"到"</"之间的空白)
  元素结束(</student>)
文档结束

SAX解析器接口和事件处理器接口在org.xml.sax包中定义。
XMLReader是SAX2.0解析器必须实现的接口。该接口允许应用程序设置和查询解析器的功能和特性,注册处理文档的事件处理器,以及启动文档的解析。

解析器提供商负责提供实现XMLReader接口的解析器类,我们只需编写事件处理器程序。
SAX API中的ContnetHandle接口是一个主要的处理器接口。如果应用程序要获得基本的解析事件就必须实现该接口,并使用XMLReader对象的setContentHandler()向解析器注册一个ContentHandler()实例。解析器使用这个实例来报告与文档相关的基本事件,例如,元素开始和结束,以及字符数据等。在这个接口中,事件的顺序是非常重要的,它反映了文档自身信息的顺序。例如,元素的所有内容(字符数据,处理指令,子元素)都依次在startElement事件和对应的endElement事件之间出现。

void setDocumentLocator(Locator locator)
该方法接收一个用于获取文档分析时产生的SAX事件定位信息的对象。该方法将在解析器报告任何其他文档事件之前被调用。作为参数传递给这个方法的定位器对象,允许应用程序测定任何与文档相关的事件的结束位置。通常,应用程序会使用这个信息来报告它自身的错误(例如,与应用程序的商业规则不匹配的字符内容)。

void startDocument() throws SAXException
该方法接收文档开始的通知。SAX解析器将在任何其它事件回调方法被调用之前调用该方法(除了setDocumentLocator方法),并只调用一次。

void endDocument() throws SAXException
该方法接收文档结束的通知。SAX解析器只调用这个方法一次,而且它是在解析过程中最后一次被调用的方法。

void startPrefixMapping(String prefix,String uri)throws SAXException
void endPrefixMapping(String prefix)throws SAXException
startPrefixMapping()在一个前缀-URI名称空间映射范围的开始时被调用。而endPrefixMapping()在前缀-URI映射范围结束时被调用。例如:下面的XML文档
<students xmlns:stu="http://www.iteye.com/students">
   .....
</students>
SAX解析器在分析到<students>元素时,就会调用startPrefixMapping(),将stu传递给prefix参数,将http://www.iteye.com/students传递给uri参数,然后产生<students>元素的startElement事件。在产生<students>元素的endElement事件后,解析器将调用endPrefixMapping(),将stu传递给prefix参数。

void startElement(String uri,String localName,String qName,Attribute atts)throws SAXException
该方法接收元素开始的通知。解析器在xml文档的每一个元素开始时调用这个方法。每一个startElement事件都有一个对应的endElement事件(即使是空元素),在endElement事件之前,元素的所有内容都被依次报告。
这个事件允许每个元素最多有三个名称部分:1.名称空间URI;2.本地名;3.限定名;是否有这几部分,取决于http://xml.org/sax/features/namespaces和http://xml.org/sax/features/namespace-prefixes属性的值.
a.当namespaces属性为true时,名称空间URI和本地名是必须的。当namespaces属性是false,那么二者是可选的(但如果指定了其中一个名称,那么另一个也必须指定)
b.当namespace-prefixes属性为true,那么限定名必需的,否则是可选的,缺省值为false.
注意:属性列表将只包含具有确切值(直接指定或缺省值)的属性,#IMPLIED属性将被忽略。只有当http://xml.org/sax/features/namespace-prefixes属性为true(缺省值为false,解析器对true值的支持是可选的),属性列表才会包括用于名称空间声明的属性(xmlns*属性)

void endElement(String uri,String localName,String qName) throws SAXException
该方法接收元素结束的通知。解析器在XML文档的每一个元素结束时调用这个方法。

void characters(char[] ch,int start,int length)throws SAXException
该方法接收字符数据的通知。解析器调用这个方法来报告字符数据块。SAX解析器会把所有连续的字符数据放在一个单独的块中返回,或者把它们分成几个数据块。不过,在任何一个单独的所有字符都必须来自同一个外部实体,以便Locator提供有用的信息(Locator要提供文档中事件结束的位置信息)。应用程序不要试图读取ch数组中指定范围以外的的数据。注意:有些解析器使用ignorableWhitespace()来报告元素内容中的空白,而不是用characters()(进行有效性验证的解析器就是如此)。

void processingInstruction(String target,String data)throws SAXException
该方法接收处理指令的通知。解析器每遇到一个处理指令就调用该方法一次。注意:处理指令可以在XML文档的根元素(文档元素)之前或之后出现。

void skippedEntity(String name)throws SAXException
该方法接收跳过的实体的通知。解析器每跳过一个实体就会调用该方法。非验证的解析器如果没有看到实体声明的话(例如实体在外部的DTD子集中的声明),可以跳过实体。所有的处理器是否跳过外部的实体取决于http://xml.org/sax/features/external-general-entities和http://xml.org/sax/features/exteral-parameter-entities属性(property)的值。

配置SAX解析器有两种方法:功能和特性。
功能包括打开和关闭某个功能。例如验证。
特性包括设置解析器所使用的特定项的值,例如设置SAX词法分析器实例。
1.功能(feature)是通过XMLReader接口中的setFeature()来设置的,例如要打开验证功能可调用setFeature(): xmlReader.setFeature("http://xml.org/sax/feature/validation",true);

注意:在SAX中每一个功能都是由一个特定的URI来标识,当前的标准功能的URI都以http://xml.org/sax/features/作为前缀,下面列出常用功能的URI:
-http://xml.org/sax/features/namespaces
如果namespace为true,则解析器执行名称空间处理。在事件处理器的相应方法中,所有元素和属性的名称空间URI和未限定的本地名称可以使用。任何SAX2.0兼容的解析器都支持将namespaces的默认值设成true。
-http://xml.org/sax/features/namespace=prefixes
如果namespace-prefixes设为true时,则解析器对名称空间前缀的解析提供支持。在事件处理器的相应方法中,XML限定名(带前缀的名称)和属性(包括xmlns*属性)将可以使用。任何SAX2.0兼容的解析器都支持将namespace-prefixes的默认值设为false。
-http://xml.org/sax/features/external-general-entities
设置解析器是否处理外部的一般实体。如果对解析器启用了验证功能。则external-general-entities将总是true。
-http://xml.org/sax/features/external-parameter-entities
设置解析器是否处理外部的参数实体。如果对解析器启用了验证功能。则external-general-entities将总是true。
-http://xml.org/sax/features/validation
设置解析器是否验证文档。如果为true,则所有的外部实体都将被处理。

2.特性(property)是通过XMLReader接口中的setProperty()来设置的。特性和功能的设置是类似的,区别是特性以对象作为参数,而功能以布尔值作为参数。例如要设置词法分析器实例 ,可调用setProperty(): xmlReader.setProperty("http://xml.org/sax/properties/lexical-handle",new MyLexicalHandler());

SAX解析器工厂:javax.xml.parsers.SAXParserFactory
如果使用Apache的Xerces解析器,可配置如下:
javax.xml.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl

SAX实例一:
SAXPrinter.java输出跟students.xml一样的数据。
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

//重写了DefaultHandler的5个方法
public class SAXPrinter extends DefaultHandler{

	@Override
	//文档开始
	public void startDocument() throws SAXException {
		//输出双引号可以用反斜杠也可输出单引号
		System.out.println("<?xml version=\"1.0\" encoding='gb2312'?>");
	}
	
	@Override
	//处理指令
	public void processingInstruction(String target, String data) throws SAXException {
		System.out.println("<?"+target+" "+data+"?>");
	}
	
	@Override
	//元素开始
	public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
		System.out.print("<"+qName);
		int len = attrs.getLength();
		for(int i=0;i<len;i++){
			System.out.print(" ");
			System.out.print(attrs.getQName(i));
			System.out.print("=\"");
			System.out.print(attrs.getValue(i));
			System.out.print("\"");
		}
		System.out.print(">");
	}
	
	@Override
	//处理字符(由空白组成的数据,可以看成格式)
	public void characters(char[] ch, int start, int length) throws SAXException {
		System.out.print(new String(ch,start,length));
	}


	@Override
	//元素结束
	public void endElement(String uri, String localName, String qName) throws SAXException {
		System.out.print("</"+qName+">");
	}

	public static void main(String[] args) {
		SAXParserFactory spf = SAXParserFactory.newInstance();
		try {
			SAXParser sp = spf.newSAXParser();
			sp.parse(new File("students.xml"),new SAXPrinter());
		} catch (ParserConfigurationException e) {
			// TODO 自动生成 catch 块
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO 自动生成 catch 块
			e.printStackTrace();
		} catch (IOException e) {
			// TODO 自动生成 catch 块
			e.printStackTrace();
		}
	}

}

SAX实例二:
ErrorProcessor.java演示错误处理器的使用
如果SAX应用程序需要实现定制的错误处理,那么它必须实现这个接口,并调用XMLReader对象的setErrorHandler()向解析器注册一个实例。之后解析器将通过这个接口报告所有的错误和
警告。
students2.xml
<?xml version="1.0" encoding="gb2312"?>

<?xml-stylesheet type="text/xsl" href="student.xsl"?>

<!DOCTYPE students[
<!ELEMENT students (student+)>
<!ELEMENT student (name,age,score)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT score (#PCDATA)>
<!ATTLIST student sn CDATA #REQUIRED>
]>

<students>
  <student sn="01">
     <name>张三</name>
     <age>11</age>
  </student>
  <student sn="02">
     <name>李四</name>
     <age>14</age>
  </student>
</students>

ErrorProcessor.java:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

//覆盖了warning(),error(),fatalError(),endElement()
public class ErrorProcessor extends DefaultHandler{

	@Override
	//警告信息
	public void warning(SAXParseException e) throws SAXException {
		System.out.println("[Warning:"+getLocationString(e)+":"+e.getMessage());
	}
	
	@Override
	//可恢复错误
	public void error(SAXParseException e) throws SAXException {
		System.out.println("[Error:"+getLocationString(e)+":"+e.getMessage());
	}

	@Override
	//不可恢复错误
	public void fatalError(SAXParseException e) throws SAXException {
		System.out.println("[FatalError:"+getLocationString(e)+":"+e.getMessage());
	}
	
	//自定义方法
	private String getLocationString(SAXParseException e){
		StringBuffer sb = new StringBuffer();
		String publicId = e.getPublicId();
		if(null != publicId ){
			sb.append(publicId);
			sb.append(" ");
		}
		String systemId = e.getSystemId();
		if(null != systemId ){
			sb.append(systemId);
			sb.append(" ");
		}
		sb.append(e.getLineNumber());//行号
		sb.append(":");
		sb.append(e.getColumnNumber());//列号
		return sb.toString();
	}
	
	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		System.out.println("</"+qName+">");
	}
	
	public static void main(String[] args) {
		try {
			XMLReader xmlReader = XMLReaderFactory.createXMLReader();
			//打开验证功能
			xmlReader.setFeature("http://xml.org/sax/features/validation",true);
			ErrorProcessor ep = new ErrorProcessor();
			xmlReader.setContentHandler(ep);
			xmlReader.setErrorHandler(ep);
			xmlReader.parse(new InputSource(new FileInputStream("students2.xml")));
		} catch (SAXException e) {
			// TODO 自动生成 catch 块
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO 自动生成 catch 块
			e.printStackTrace();
		} catch (IOException e) {
			// TODO 自动生成 catch 块
			e.printStackTrace();
		}
		
	}

}

SAX实例三:查找students.xml中特定学生的信息。
利用栈的数据结构来处理XML
StudentLookup.java
import java.io.File;
import java.io.IOException;
import java.util.Stack;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;


public class StudentLookup extends DefaultHandler{
	
	private String name;
	private String age;
	private String attrName;
	private String attrValue;
	private Stack tagsStack = new Stack();
	
	public void setAttrName(String attrName) {
		this.attrName = attrName;
	}

	public void setAttrValue(String attrValue) {
		this.attrValue = attrValue;
	}
	
	@Override
	public void startElement(String arg0, String localName, String qName, Attributes attrs) throws SAXException {
		if(tagsStack.empty()){
			if("student".equals(qName)){
				int len = attrs.getLength();
				for(int i=0;i<len;i++){
					if(attrName.equals(attrs.getQName(i)) && attrValue.equals(attrs.getValue(i))){
						tagsStack.push(qName);
						break;
					}
				}
			}
		}else{
			tagsStack.push(qName);
		}
	}

	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		if(!tagsStack.empty()){
			String tag = (String)tagsStack.peek();
			if("name".equals(tag)){
				name = new String(ch,start,length);
			}
			if("age".equals(tag)){
				age = new String(ch,start,length);
			}
		}
	}

	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		if(!tagsStack.empty()){
			String tag = (String)tagsStack.pop();
			if(tagsStack.empty() && "student".equals(tag)){
				System.out.println("name"+name);
				System.out.println("age"+age);
				throw new SAXException("找到了匹配的学生");
			}
		}
	}

	@Override
	public void endDocument() throws SAXException {
		System.out.println("没有找到匹配的学生");
	}
	
	public static void main(String[] args) {
		if(args.length!=1){
			System.out.println("Usage:java StudentLookup key=value");
			System.exit(1);
		}
		int index = args[0].indexOf("=");
		if(-1 == index){
			System.out.println("Usage:key-value");
			System.exit(1);
		}
		String str = args[0].substring(0,index);
		StudentLookup sl = new StudentLookup();
		sl.setAttrName(str);
		str = args[0].substring(index+1);
		sl.setAttrValue(str);
		SAXParserFactory spf=SAXParserFactory.newInstance();	
		try{
			SAXParser sp=spf.newSAXParser();
			sp.parse(new File("students.xml"),sl);
		}
		catch (ParserConfigurationException e){		
			e.printStackTrace();
		}
		catch (SAXException e){
			System.out.println(e.getMessage());
		}
		catch (IOException e){
			e.printStackTrace();
		}
	}
	
}
分享到:
| DOM
评论

相关推荐

    SAX的jar包 SAX的jar包

    SAX的jar包 SAX的jar包SAX的jar包 SAX的jar包 SAX的jar包

    sax.jar sax.jar

    sax.jar sax.jar sax.jar sax.jar sax.jar sax.jar sax.jar

    SAX解析XML文件实例

    SAX解析XML文件的实例。一个项目同时用dom解析和sax解析xml文件貌似会报错,项目框架建一直是用sax和dom4j解析xml文件的。当我用dom解析xml文件。导入包后就报错识别不了xml文件的编码格式。于是做了一个sax解析xml...

    android 使用Sax解析XML 源码实例

    使用SAX方式解析XML SAX 是读取和操作 XML 数据的更快速、更轻量的方 法。SAX 允许您在读取文档时处理它,从而不必等待整个文档被存储之后才采取操作。它不涉及 DOM 所必需的开销和概念跳跃。 SAX API是一个基于事件...

    SAX符号化序列范例源码

    SAX符号化序列范例源码 -------------------- timeseries2symbol.m: -------------------- This function takes in a time series and convert it to string(s). There are two options: 1. Convert the entire...

    dom解析和sax解析

    dom和sax解析的区别,dom的概念,sax的概念

    dom.sax.pull解析

    Java解析XML的三种方式 ...Ø 2、SAX(org.xml.sax) Ø SimpleAPI for XML,以事件的形式通知程序,对Xml进行解析。 Ø 3、XMLPULL(org.xmlpull.v1) Ø 类似于SAX方式,程序以“拉取”的方式对Xml进行解析。

    QT使用SAX读取xml高效-快速.rar

    QT使用SAX读取xml高效-快速.rar SAX(Simple API for XML) 如果你只想读取并显示整个XML文档,那么SAX是很好的选择,因为它提供了比DOM更简单的接口,并且它不需要将整个XML文档一次性读入内存,这样便可以用来读取...

    sax9.0解析XML

    sax9.0 sax9.0 sax9.0 sax9.0 sax9.0 sax9.0 sax9.0

    dom4j下sax解析xml

    项目下包含dom4j的包 是里用dom4j的sax解析方式 sax解析打文件比dom速度快,该项目为测试项目

    SAX 实例教程及代码

    SAX 教程及代码 SAX 教程及代码 SAX 教程及代码 SAX 教程及代码

    SAX解析网络编程

    SAX,网络编程,解析工具,SAX解析网络编程

    SAX类解析XML

    SAX类解析XML

    西门子执行器SAX61.03

    西门子SAX61.03说明书,最新的执行器。注意接线端子不能接反

    Android之SAX解析XML

    Android之SAX解析

    SAX for .net(sax的适用于.net版)

    SAX是Simple API for XML的缩写。 SAX在概念上与DOM完全不同。首先,不同于DOM的文档驱动,它是事件驱动的,也就是说,它并不需要读入整个文档,而文档的读入过程也就是SAX的解析过程……

    天气预报接口,通过sax 解析接口数据

    接口交互数据,通过sax解析xml。自己写的天气预报结果数据的解析。

    SAX.java 操作xml文件

    SAX.java 操作xml文件SAX.java 操作xml文件SAX.java 操作xml文件SAX.java 操作xml文件SAX.java 操作xml文件SAX.java 操作xml文件SAX.java 操作xml文件SAX.java 操作xml文件

    SAX解析XML源码

    SAX解析XML源码:安卓客户端程序,通过HTTP协议从服务器端获取XML文件,然后解析并输出到控制台

    Sax解析XML文件解析

    Sax解析XML文件解

Global site tag (gtag.js) - Google Analytics