android使用XML-----SAX

ØHTTP网络传输中的数据组织方式有三种方式:
Ø
Ø 1 HTML 方式
Ø
Ø 2 XML 方式
Ø
Ø 3 JSON 方式
Java Sax解析是按照xml文件的顺序一步一步的来解析,在解析xml文件之前,我们要先了解xml文件的节点的种类,一种是ElementNode,一种是TextNode。如下面的这段book.xml
Ø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>



ØXML的结构解析如下:
Ø 1 、节点
Ø 2 、元素
Ø 3 、属性和属性值
Ø 由于 XML 的扩展性强,致使它需要有稳定的基础规则来支持扩展,该语法规则是:
Ø 1 、开始和结束标签匹配
Ø 2 、嵌套标签不能互相嵌套
Ø 3 、区分大小写

其中,像<books>、<book>这种节点就属于ElementNode,而thinking in java、85.5这种就属于TextNode。

下面结合一张图来详细讲解Sax解析。


xml文件被Sax解析器载入,由于Sax解析是按照xml文件的顺序来解析,当读入<?xml.....>时,会调用startDocument()方法,当读入<books>的时候,由于它是个ElementNode,所以会调用startElement(String uri, String localName, String qName, Attributes attributes) 方法,其中第二个参数就是节点的名称,注意:由于有些环境不一样,有时候第二个参数有可能为空,所以可以使用第三个参数,因此在解析前,先调用一下看哪个参数能用,第4个参数是这个节点的属性。这里我们不需要这个节点,所以从<book>这个节点开始,也就是图中1的位置,当读入时,调用startElement(....)方法,由于只有一个属性id,可以通过attributes.getValue(0)来得到,然后在图中标明2的地方会调用characters(char[] ch, int start, int length)方法,不要以为那里是空白,Sax解析器可不那么认为,Sax解析器会把它认为是一个TextNode。但是这个空白不是我们想要的数据,我们是想要<name>节点下的文本信息。这就要定义一个记录当上一节点的名称的TAG,在characters(.....)方法中,判断当前节点是不是name,是再取值,才能取到thinking in java。


ØAndroid中,解析Xml数据的三种方式:

Ø
Ø 1 DOM(org.w3c.dom)
Ø 文档对象模型”方式,解析完的 Xml 将生成一个树状结构的对象。
Ø
Ø 2 SAX( org.xml.sax )
Ø Simple API for XML ,以事件的形式通知程序,对 Xml 进行解析。
Ø
Ø 3 XMLPULL(org.xmlpull.v1)
Ø 类似于 SAX 方式,程序以“拉取”的方式对 Xml 进行解析。

第一种方法:SAX

Ø SAX 是一种以事件驱动的 XML api ,由它定义的事件流可以指定从解析器传到专门的处理程序的代码的 XML 结构,简单的讲,它解析速度快,占用内存少的解析器。这种解析器比较适合 android 等移动设备。
Ø
Ø 使用 SAX 的优点是:
Ø
Ø 因为 SAX 的优势是流的方式处理,当遇到一个标签的时候,并不会记录下当前所碰到的标签。
Ø
Ø 也就是说, startEelment 方法中,你所知道的信息,仅仅是当前的签名的名字和属性,至于标签的嵌套结构,上层标签的名字,是否有子元素与其他结构相关的信息,都是不知道的。

看一下JDK中SAX的结构:

这里面:DocumentHandler已经过时,取而代之的是ContentHandler

DTDHandler几乎不怎么使用,都使用EntityResolver;
最主要的一个实现类:
DefaultHandler
所有已实现的接口:
ContentHandler, DTDHandler, EntityResolver, ErrorHandler

DefaultHandler主要方法:
startDocument() endDocuemnt()
void StartElement(String uri String lname String qname Atrributes attr)   这里查寻每个参数的解释,Attributes是一个重要的类
endElement()
void character(char[] data,int start , int length)data是文本内容。


解析器类:
SAXParserFactory类:newInstance()  注意提前设置: setNamespaceAware() setValidating()
SAXParser类:Parser(FIle|InputStream|URL,Handler);getXMLReader()

XMLReader类:

XMLReader 是 XML 解析器的 SAX2 驱动程序必须实现的接口。此接口允许应用程序设置和查询解析器中的功能和属性,注册文档处理的事件处理程序,以及开始文档解析。

此接口取代了(现在不推荐) SAX 1.0 Parser 接口。与旧的解析器接口(和某些监控器接口)相比,XMLReader 接口具有两大重要增强:

  1. 它增加了查询和设置功能和属性的标准方法;并且
  2. 增加了对名称空间的支持,这是许多高层的 XML 标准所必需的。 
在SAXParser中的getXMLReader()方法中可以获取  该Parser的各种Handler


方法摘要
 ContentHandlergetContentHandler()
          返回当前的内容处理程序。
 DTDHandlergetDTDHandler()
          返回当前的 DTD 处理程序。
 EntityResolvergetEntityResolver()
          返回当前的实体解析器。
 ErrorHandlergetErrorHandler()
          返回当前的错误处理程序。
 booleangetFeature(String name)
          查找功能标志的值。
 ObjectgetProperty(String name)
          查找属性的值。
 voidparse(InputSource input)
          解析 XML 文档。
 voidparse(String systemId)
          从系统标识符 (URI) 解析 XML 文档。


服务器端:

客户端:

Test.java
package com.sax.test;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;

import com.sax.http.HttpUtils;
import com.sax.service.SaxService;

public class Test {

	public Test() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String path = "http://192.168.0.101:8080/myhttp/person.xml";
		InputStream inputStream = HttpUtils.getXML(path);
		if(inputStream==null){
			System.out.println("sss");//说明输入流为null
		}
		try {
			List<HashMap<String, String>> list = SaxService.readXML(
					inputStream, "person");
			for (HashMap<String, String> map : list) {
				System.out.println(map.toString());
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
	}

}

SaxService.java
工厂模式:
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser parser = spf.newSAXParser();// 解析xml
MyHandler handler = new MyHandler(nodeName);
parser.parse(inputStream, handler);

package com.sax.service;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import com.sax.handler.MyHandler;

public class SaxService {

	public SaxService() {
		// TODO Auto-generated constructor stub
	}

	public static List<HashMap<String, String>> readXML(
			InputStream inputStream, String nodeName) {
		try {
			// 创建一个解析xml的工厂对象
			SAXParserFactory spf = SAXParserFactory.newInstance();
			SAXParser parser = spf.newSAXParser();// 解析xml
			MyHandler handler = new MyHandler(nodeName);
			parser.parse(inputStream, handler);
			inputStream.close();
			return handler.getList();
		} catch (Exception e) {
			// TODO: handle exception
		}
		return null;
	}
}

MyHandler.java
最主要的类,

package com.sax.handler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.jar.Attributes.Name;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class MyHandler extends DefaultHandler {

	private HashMap<String, String> map = null;// 存储单个解析的完整对象
	private List<HashMap<String, String>> list = null;// 存储所有的解析对象
	private String currentTag = null;// 正在解析的元素的标签
	private String currentValue = null;// 解析当前元素的值
	private String nodeName = null;// 解析当前的节点名称

	public MyHandler(String nodeName) {
		// TODO Auto-generated constructor stub
		this.nodeName = nodeName;
	}

	public List<HashMap<String, String>> getList() {
		return list;
	}

	@Override
	public void startDocument() throws SAXException {
		// TODO Auto-generated method stub
		// 当读到第一个开始标签的时候,会触发这个方法
		list = new ArrayList<HashMap<String, String>>();
	}

	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		// 当遇到文档的开头的时候,调用这个方法
		System.out.println("-->>startElement "+qName);
		if (qName.equals(nodeName)) {
			map = new HashMap<String, String>();
			if (attributes != null && map != null) {
				for (int i = 0; i < attributes.getLength(); i++) {
					map.put(attributes.getQName(i), attributes.getValue(i));
				}
			}
			System.out.println(map.toString());
		}
		
		
		currentTag = qName;
	}

	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		// TODO Auto-generated method stub
		// 这个方法是用来处理xml文件所读取到的内容
		System.out.println("characters-->>"+ch.toString());
		if(currentTag== null){
			System.out.println("-->>当前节点为空");
		}else{
			System.out.println("-->>当前节点为"+currentTag);
		}
		if (currentTag != null && map != null) {
			currentValue = new String(ch, start, length);
			if (currentValue != null && !currentValue.trim().equals("")
					&& !currentValue.trim().equals("\n")) {
				map.put(currentTag, currentValue);
			}
		}
		currentTag = null;// 把当前的节点的对应的值和标签设置为空
		currentValue = null;

	}

	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		// TODO Auto-generated method stub
		// 遇到结束标记的时候,会调用这个方法
		if (qName.equals(nodeName)) {
			list.add(map);
			map = null;
		}
		super.endElement(uri, localName, qName);
	}
}


工具类HttpUtil
package com.sax.http;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class HttpUtils {

	public HttpUtils() {
		// TODO Auto-generated constructor stub
	}

	public static InputStream getXML(String path) {
		InputStream inputStream = null;
		try {
			URL url = new URL(path);
			if (url != null) {
				HttpURLConnection connection = (HttpURLConnection) url
						.openConnection();
				connection.setConnectTimeout(3000);
				connection.setDoInput(true);
				connection.setRequestMethod("GET");
				int code = connection.getResponseCode();
				if (code == 200) {
					inputStream = connection.getInputStream();
				}
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
		return inputStream;
	}
}
执行结果:
-->>startElement persons
characters-->>[C@1ef3212
-->>当前节点为persons
-->>startElement person
{id=23}
characters-->>[C@1ef3212
-->>当前节点为person
-->>startElement name
characters-->>[C@1ef3212
-->>当前节点为name
characters-->>[C@1ef3212
-->>当前节点为空
-->>startElement age
characters-->>[C@1ef3212
-->>当前节点为age
characters-->>[C@1ef3212
-->>当前节点为空
characters-->>[C@1ef3212
-->>当前节点为空
-->>startElement person
{id=20}
characters-->>[C@1ef3212
-->>当前节点为person
-->>startElement name
characters-->>[C@1ef3212
-->>当前节点为name
characters-->>[C@1ef3212
-->>当前节点为空
-->>startElement age
characters-->>[C@1ef3212
-->>当前节点为age
characters-->>[C@1ef3212
-->>当前节点为空
characters-->>[C@1ef3212
-->>当前节点为空
{id=23, age=21, name=张老师}
{id=20, age=25, name=李老师}

说明:
1)每碰到<>或</>触发StartElement
2)在触发完StartElement之后就会立刻触发Character函数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值