XML学习《SAX解析》
来源:互联网 发布:阿里云改系统 编辑:程序博客网 时间:2024/04/27 18:32
1.01SAX解析器及工作原理
SAX(Simple API for XML)提供了解析XML文件的API,和DOM解析器比,不用将XML文件读入内存建立树状结
构。SAX的 核心是事件处理机制,SAX解析器调用: parse(File f,DefaultHandler dh);
解析XML文件,并向该方法传递一个事件处理器。SAX解析器在解析XML文件是过程中,根据从文件中解析出来
的数据产生相应的事件,并报告这个事件给事件处理器,事件处理器就会处理所发现的数据,parse方法必须等
待事件处理完毕后再继续解析文件,报告下一个事件,因此,对于SAX来说,较DOM解析器更高的效率,事件处
理器每次在内存中只保留对一个事件的处理,处理完毕后即可释放该处理过程所占用的内存。
使用SAX解析器的步骤如下:
1: SAXParserFactory factory= SAXParserFactory.newInstance();
2: SAXParser saxParser = factory.newSAXParser();
同时要使用到javax.xml.parsers这个包。
如果想要SAXParserFactory产生的SAX解析支持名称空间的话,
可让factory对象调用setNamespaceAware(true)。
1.02:事件处理器
SAX解析器使用下述方法解析XML文件:
public void parse(File,DefaultHandler) throws SAXException,IOException;
public void parse(InputStream,DefaultHandler) throws SAXException,IOException;
public void parse(String,DefaultHandler) throws SAXException,IOException;
1.03:事件的产生与处理
SAX解析器的核心是事件处理机制,当SAX解析器调用parse()方法解析XML文件时,事件处理器会根据所产生的
事件调用相应的方法来处理发现的数据,在编写程序时,需要使用DefaultHandler类的子类创建一个事件处理
器,当处理器对报告的事件不感性趣时,就直接调用父类的方法,采用默认的处理方法,当处理器对报告的事件
感性趣时,子类可以重写父 类的某些方法,调用重写的方法,以便处理器可以具体的处理解析器报告的数据。
1.04:文件的开始与结束
当解析器开始解析XML文件时,就会报告"文件开始"事件,事件给事件处理器,然后再陆续地报告其他的事件,
比如:"开始标记","文本事件",最后再报告"文件结束"事件。解析器报告"文件开始"事件,事件处理器就会调用:
startDocument()方法,解析器报告"文件结束"事件,事件处理器会调用endDocument()方法,解析器在解析XML
文件的过程中,只能报告一次"文件开始"和"文件结束"事件,换句话说,也只会调用一次startDocument()和
endDocument()方法各一次。
1.05:XML中的处理指令
XML中的处理指令比较特殊,它们不属性标记,它们为XML文件规定了特殊的规则,例如:
<?xml version="1.0" encoding="UTF-8"?>
处理指令规定XML文件必须使和UTF-8编码来保存和解析,解析器不报告XML声明给事件处理器,即不会报告上述
指令。 但如下XML指令会报告给事件处理器:<?xml-stylesheet href="" type=""?>
当解析器开始解析XML文件时,如果发现处理指令就会报告一个"处理指令"事件给事件处理器,事件处理器就会
调用 void processingInstruction(String target,Strin data)方法,该方法中的参数target和data就是解析发现的数
据。
例如:对于<?xml-stylesheet href="" type=""?>处理指令,
target就是"xml-stylesheet",data就是"href="" type="""
1.06开始标记与结束标记
当解析器发现一个标记开始时,就将所发现的数据封装为一个"开始标记"事件,并报告该事件处理器,事件处理
器就会知道发生的事件,然后调用:
startElement(String uri,String localName,String qName,Attributes atts);
方法对发现的数据处理,方法中的参数atts是解析器发现的标记的全部属性,当SAXParserFactory支持设置名称
空间时,例如:factory.setNamespaceAware(true);
参数uri的取值就是解析器发现的标记的名称空间,如果没有名称空间,uri是空字符组成的串,uri="",
localName是标记的名称,qName是带名称空间前缀的标记名称(如果有名称空间的前缀)或标记的名称(如果没有
名称空间的前缀)。
当SAXParserFactory对象没有设置支持名称空间时,相当于,factory.setNamespaceAware(false);
那么uri和localName的值是空字符串,qName是带名称空间前缀的标记名称(如果有名称空间的前缀)或标记名称
(如果没有名称空间的前缀)。
事件处理器调用完startElement方法后,将陆续地收到解析器报告的其他事件,最后一定会报告该标记的
"标记结束"事件,这时事件处理器会调用:
endElement(String uri,String localName,String qName,Attributes atts);
方法对发现的数据做出处理。
如果一个标记是空标记,解析器也报告"标记开始"和"标记结束"事件。
1.07:文本数据
XML文件中的标记的内容可以有文本数据,当解析器解析这些数据时,就报告"文本数据"事件给处理器,事件处
理器就会知道发生的事件,然后调用:
public void characters(char[] int start,int length);
方法对解析的数据做出处理,参数字符数组ch中存放的就是解析的文本数据,start是数组ch中存放字符的起始位
置,length是存放字符的个数。标记之间的缩格都是为了使XML文件看起来美观而形成的,但解析器不知道这一
点,所以解析也会认为他们是有用的文本数据,当解析器解析这样的数据时,也会报告一个"文本事件"给事件处
理器。注意:对于文本数据,解析器可能分成几个连续的"文本数据"报告给事件处理器。
1.08:处理空白
标记之间的缩格都是为了使XML文件看起来美观而形成的,但解析器不知道这一点,所以解析也会认为他们是有
用的文本数据,当解析器解析这样的数据时,也会报告一个"文本事件"给事件处理器。
这些文本可能由空白类字符组成。
例如:
<?xml version="1.0"?>
<root>
<a>hello</a>
<b>你好</b>
</root>
SAX解析器并不知道标记之间的缩进区域是为了使得XML文件看起来更美观,对于上述XML文件,解析器一共报
告了5次"文本数据"事件给事件处理器。显然,我们可能不希望事件处理器去调用characters方法来处理标记之间
的缩 进区域所形成的空白字符,因为这样会延时事件处理器获取其他数据的时间。如果不想让事件处理 器去调
用characters方法来处理的话,那么XML必须有效的,而且所关联的DTD文件必须规定XML文件的标记不能有混
内容, 一旦这样做,当解析器报告的"文本数据"事件属于标记之间的缩进区域所形成的空白类字符时,事件处理
器就会去调用:
ignorableWhitespace(char[] ch,int start,int length); 方法,而不会调用character()方法。
如果我们不准备处理这些空白,只要在编写DefaultHandler为的子类时直接从父类继承该方法即可,如果准备处
这些空白类字符,只要在子类重写ignorableWhitespace方法即可。
1.09:名称空间
名称空间的目的是有效的区分名字相同的标记,当二个标记的名字相同时,他们可能通过属于不同的名称空间来
区分。名称空间通过使用声明名称空间来建立,分为有前缀和无前缀的名称空间。
名称空间声明是在一个标记的开始标记中,当解析器在一个标记的开始标记中发现一个名称空间时,就先报告一
个 "名称空间开始"的事件给事件处理器,然后再报告"开始标记"事件。事件处理器会调用:
startPrefixMapping(String prefix,String uri)
其中:方法中的参数prefix是解析器发现的名称空间的前缀,uri是名称空间的名称,如果名称空间没有前缀,prefix
是不含任何字符的空串,即prefix=""。名称空间涉及到作用域的概念,一个标记如果使用了名称空间,那么该名
称空间的作用域是该标记及其子标记,因此,当解析报告完"结束标记"事件后,就会报告一个"名称空间结束"事件
给事件处理器,表明名称空间的作用域结束,事件处理器就会知道发生的事件,然后调后:
endPrefixMapping(String prefix,String uri)
例如:<hello xmlns:java="eee">你好</hello>
解析器报告事件的顺序如下:
"名称空间开始"-->"开始标记"-->"文本数据"-->"结束标记"-->"名称空间结束"
为了让解析器报告"名称空间"事件,SAXParser_Factory需要调用setNamespaceAware(true)。
1.10:处理错误
SAX解析器默认地检查XML是否规范的,如果让SAX解析器检查XML文件是否有效,SAXParserFactory对象
factory事件 必须进行如下设置:
factory.setValidating(true);SAX解析器在解析XML文件的过程中,如果发现错误就会报告一 个"错误"事件给解析,
报告的信息是一个SAXParserExcepiton对象,事件处理就会调用下列某个方法来处理信息:
public void warning(SAXException e) throws SAXException;
public void error(SAXException e) throws SAXException;
public void fatalError(SAXException e) throws SAXException;
1.11不可解析实体
实体分为可以被解析的实体和不可以被解析的实体,可解析实体就是能被解析器解析的实体。
例如:你好,<中国>
不可解析实体就是解析器无法解析的数据,通常指二进制数据,XML文件中不可以引用不可解析实体。
例如:你好,&中国
外部实体和内部实体有很大的不同,我们引用的外部实体可以是文本数据或是二进制数据,而且编码也可能和我
们的XML不同。
例如: 一个外部实体内容为:你you
并没有包括任何特殊字符,但该文件的保存存编码可能是ANSI或其他编码,但不是UTF-8,ANSI使用2个字节编
码"你",而UTF-8编码使用3个编码"你",那么解析器将文件的实际内容和引用该文件的XML放在一起做解析时,
就会发现UTF-8不支持 编码值"你",从而导致错误。
1.12关于SAXException异常
在使用SAX处理解析过程中出现的错误,当发生致命的错误时,应用抛出一个SAXException对象给解析器,解析
器将停止parse方法的执行。
实际上,DefaultHandler类中的方法都可以抛出一个SAXException对象给解析器,比如,事件处理器在调用
startDocument()方法时,突然决定终止解析文件,就可以抛出一个SAXException对象给解析器,解析器停止
parse方法的 执行,不再报告任何事件给事件处理器。
一个完整的例子
example.xml:
<?xml version="1.0" ?>
<guest>
<spent name="weng">1213</spent>
<spent name="li">3213</spent>
<spent name="rui">213</spent>
<spent name="weng">6213</spent>
<spent name="weng">2088</spent>
<spent name="zhang">1013</spent>
</guest>
<!--========SaxXml.java============== -->
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.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class SaxOne extends DefaultHandler {
public static int count = 0 ;
public static void main(String[] args){
File file = new File("I://JAVA//Eclipse//XmlDemo//ch5-3.xml");
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
try {
SAXParser parser = saxFactory.newSAXParser();
parser.parse(file,new SaxOne());
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
System.out.println("/n事件处理器处理了"+ count +"个事件");
}
public void startDocument() throws SAXException{
System.out.println("开始解析XML文件");
count ++;
}
public void startElement(String uri,String localName,String qName,Attributes attributes)
throws SAXException{
System.out.print("<"+qName+">");
count++;
}
public void endDocument() throws SAXException{
System.out.println();
System.out.println("结束解析XML文件");
count ++;
}
public void endElement(String uri, String localName, String qName) throws SAXException{
System.out.print("</" + qName + ">");
count ++;
}
public void characters(char[] ch,int start,int length) throws SAXException{
System.out.print(new String(ch,start,length));
count ++;
}
public void processingInstruction(String target, String data) throws SAXException{
System.out.println("处理指令的目标是" + target);
System.out.println("处理指令的内容是" + data);
}
public void setDocumentLocator(Locator locator){
System.out.println(locator.getColumnNumber() + ":" + locator.getLineNumber());
}
}
- XML学习《SAX解析》
- 学习sax解析xml
- SAX解析XML:学习
- Android学习-Sax解析XML
- XML学习之SAX解析XML文件
- SAX解析xml学习笔记[1]
- Java解析XML学习笔记(SAX篇)
- xml学习笔记(5)sax解析
- Android学习笔记--解析XML之SAX
- android学习笔记16: SAX解析XML
- 学习笔记--sax解析xml文档
- android 学习笔记 SAX 解析XML数据
- XML语言学习4--SAX解析
- android SAX解析XML学习笔记
- XML学习总结-SAX解析-(三)
- [XML] SAX解析XML
- 【XML】SAX解析XML
- XML解析(SAX解析)
- CMWAP和CMNET 的主要区别与适用范围
- Linux关机命令详解
- time_t与struct tm C/C++中的日期和时间
- 家庭电路
- Attentions About Creating Database through Store Procedure
- XML学习《SAX解析》
- 类UNIX操作系统ROOT密码破解
- Request.Form.Get()
- 解决问题(三)——Exception
- BI部门架构
- 怎样选一个好的域名
- COM+组件安全....
- Windows服务程序解决企业短信统一处理解决方案及源码参考
- cOM 指针