Java解析XML学习笔记(SAX篇)


SAX 的解析步骤:
(1)写一个类继承 DefaultHandler, 实现自己的事件处理方法
(2)在主程序中建立 SAXParserFactory
(3)可以设置这个factory 的参数
(4)从这个factory 得到SAXParser
(5)解析XML文件
获取输入源
InputSource is = new InputSource(InputStream byteStream);
资源来源于文件:
InputSource is = new InputSource(getResources().openRawResource(R.raw.xmltwitter));
资源来源于字符串String:
String   str   =   "";//add   your   string   content
InputStream   inputStream   =   new ByteArrayInputStream(str.getBytes());
资源来源于网络(如RSS订阅,WebService等):
// setup the url
String urlString = "http://feed.xxx.com";
java.net.URL url = new URL(urlString);
InputSource is = new InputSource(url.openStream());
解析流程
首先需要根据已知的XML文件的约定,创建一个继承DefaultHandler 的子类。
注:SAX 解析器是一个基于事件的解析器,这就意味着使用 SAX 进行解析时要建立真实文件。
在文档开始和结束、标记开始和结束、发现数据时,事件被触发。这意味着您必须定义一个数据结构来保留感兴趣的数据、抛弃余下的。所以实际上的解析工作,是在这个Handler 里进行的。

重写以下这几个父类的方法
//通知文档开始,如需初始化,可在此方法里面处理
public void startDocument() throws SAXException;
//通知文档结束		
public void endDocument() throws SAXException;
//文档节点开始		
public void startElement(String namespaceURI, String localName, String qName,Attributes atts) 
				 throws SAXException;
//文档节点结束		
public void endElement(String namespaceURI, String localName, String qName)
			throws SAXException;
		
public void characters(char ch[], int start, int length);


现在先解析下面这个简单的XML文件xmlFile.xml,看看这几个方法是什么时候调用,用在什么地方。

<root><!--注意这里有个换行符-->
</root>

上面5个需要重写的方法仅仅做一件事:输出该方法的方法名:

int i = 1;

public void startDocument() throws SAXException{
	System.out.println(i++);
	System.out.println(".startDocument()");
}
	
public void endDocument() throws SAXException{
	System.out.println(i++);
	System.out.println(".endDocument()");
}
		
public void startElement(String namespaceURI, String localName, String qName,Attributes atts) 
				 throws SAXException{
	System.out.println(i++);
	System.out.println(".startElement()");
}
		
public void endElement(String namespaceURI, String localName, String qName)
			throws SAXException{
	System.out.println(i++");
	System.out.println(".endElement()");
}
		
public void characters(char ch[], int start, int length){
	System.out.println(i++);
	System.out.println(".characters()");
}


具体运行代码如下 SAXDemo.java

import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.*;
import org.xml.sax.*;

public class SAXDemo extends  DefaultHandler{
	private int i = 1;//记录执行序号	
	public void startDocument(){
		System.out.print(i);i++;
		System.out.println(".startDocument");
	};

	public void startElement(String uri,String localName,
			String qName,Attributes attributes){
			System.out.print(i++);
			System.out.println(".startElement");
	}
			
	public void characters(char[] ch,int start,	int length){
			System.out.print(i++);
			System.out.println(".characters");
		}
	public void endElement(String uri,String localName,String qName){
			System.out.print(i);i++;
			System.out.println(".endElement");
	}
	public void endDocument(){
			System.out.print(i);i++;
			System.out.println(".endDocument");
	}
	//解析xmlFile.xml文件
	public static void main( String[] args ){
		try{
			DefaultHandler dh = new MySaxParser();
			SAXParserFactory spf = SAXParserFactory.newInstance();
			SAXParser sp = spf.newSAXParser();
			sp.parse( "xmlFile.xml", dh );
		}catch( Exception e ){
			e.printStackTrace();
		}
	}
}


运行后,你会看到如下面的结果

1.startDocument()
2.startElement()
3.characters()
4.endElement()
5.endDocument()


再解析如下的XML

<root></root>

控制台会输出:

1.startDocument()
2.startElement()
3.endElement()
4.endDocument()

以及

<root>
       <sub>SUB</sub>
</root>

控制台输出

1.startDocument()
2.startElement()
3.characters()
4.startElement()
5.characters()
6.endElement()
7.characters()
8.endElement()
9.endDocument()

以及

<root><sub>SUB</sub><root>

控制台输出

1.startDocument()
2.startElement()
3.startElement()
4.characters()
5.endElement()
6.endElement()
7.endDocument()

目前可以得出以下结论:

1.每个Document开始,都会调用startDocument(),仅调用一次。

2.对于每一个节点 ,都会调用startElement(),如果不是叶子节点(即最底层的节点),还会继续调用startElement()。
如上面,顺序是: startElement()[解析<root>] --- startElemtnt() [解析<sub>] --- endElement()[解析</sub>] --- endElement()[解析</root>]

3.在节点与节点之间,如有任意字符(包括回车,换行符,空格等),都会执行characters()进行检查,无论是
开始节点 与 结束节点 之间(如<sub> & </sub>),
开始节点 与 开始节点 之间(如<root> & <sub>),
结束节点 与 开始节点 之间(如</sub> & <sub2>,假设同级有<sub2>,可自行测试),
结束节点 与 结束节点 之间(如</sub> & </root>).

4.访问节点的算法属于深度遍历,有点像二叉树前序算法遍历访问。(这个纯粹个人观点,对实际的解析算法理解比较浅显)


清楚了整个解析的流程,那么什么时候从xml取得对应元素的值,赋值到对应的 结果输出字符串,或者 对应的 JavaBean,就由程序员使用一个布尔值来控制了。


最后,再说说两点,一个就是startElement(String uri, String localName, String qName, Attributes attributes) 方法中各参数的简单意义。
URI:命名空间的URI,
localName:不带命名空间前缀的标签名,通常获得标签字串的就是用这个 
qName:带命名空间前缀的标签名
attributes:可以得到所有的属性名和相应的值。
	//常用使用下面的方法取得是属性名和相应的值

	String value = org.xml.sax.Attributes.getValue(int index);// 获得 相应的值
	
	String name = org.xml.sax.Attributes.getQName(int index);// 获得 属性名
另外要说的就是上面提到“SAX 解析步骤”的实现代码:
		// create the factory 创建工厂类
		SAXParserFactory factory = SAXParserFactory.newInstance();
		// create a parser 创建解析器
		SAXParser parser = factory.newSAXParser();
		// create the reader (scanner) 创建Reader类
		XMLReader xmlreader = parser.getXMLReader();


其实,最后解析的方法还可以用以下几个方法SAXParser.parse();

public void parse(String uri, DefaultHandler dh) throws SAXException, IOException ;//上面的SAXDemo.java就是使用这一个方法

public void parse(File f, DefaultHandler dh) throws SAXException, IOException;

public void parse(InputSource is, DefaultHandler dh) throws SAXException, IOException;

public void parse(InputStream is, DefaultHandler dh) throws SAXException, IOException;


本来想在这文章里面提供一个示例代码,再写到最后的时候,找到一篇很好的分析SAX原理文章,里面也附上了相关的例子,

《使用SAX读取XML文件》http://justsee.iteye.com/blog/923439

我相信,看完之后会对SAX的使用有更深刻的理解。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值