您的位置:首页 > 移动开发 > Android开发

android学习二十二(使用SAX解析xml)

2015-01-07 21:54 363 查看
          上一篇博客是使用Pull解析xml文件的,Pull解析方式虽然非常好用,但它并不是我们唯一的选择。SAX解析也是一种特别常用的XML解析方式,虽然它的用法比Pull解析复杂,但在语义方面会更加的清楚。

        通常情况下我们都会新建一个类继承自DefaultHandler,并重写父类的五个方法,如下所示:

package com.jack.networktest;

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

public class MyHandler extends DefaultHandler {

@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// TODO Auto-generated method stub
super.characters(ch, start, length);
}

@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
super.endDocument();
}

@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// TODO Auto-generated method stub
super.endElement(uri, localName, qName);
}

@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
super.startDocument();
}

@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
super.startElement(uri, localName, qName, attributes);
}

}


       startDocument()方法会在开始xml解析的时候调用,startElement方法会在开始解析某个节点的时候调用,

 characters方法会在获取节点中内容的时候调用,endElement方法会在完成解析某个结点的时候调用,endDocument()方法会在完成xml解析的时候调用。其中,startElement, characters和endElement这三个方法是有参数的,从xml中解析出的数据就会以参数的形式传入到这些方法中。需要注意的是,在获取结点中内容时,characters方法可能会被调用多次,一些换行符也被当作内容解析出来,我们需要针对这种情况在代码中做好控制。

        那么下面就让我们尝试调用SAX解析的方式来实现和前面博客同样的功能。新建一个ContentHandler类继承自

   DefaultHandler,并重写父类的五个方法,如下所示: 

package com.jack.networktest;

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

import android.util.Log;

public class ContentHandler extends DefaultHandler {

private String nodeName;
private StringBuilder id;
private StringBuilder name;
private StringBuilder version;
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// TODO Auto-generated method stub
//super.characters(ch, start, length);
//根据当前的结点名判断将内容添加到哪一个StringBuilder对象中
if("id".equals(nodeName)){
id.append(ch,start,length);
//Log.d("ContentHandler", "id.append(ch,start,length); "+id.toString().trim());
}else if("name".equals(nodeName)){
name.append(ch,start,length);
}else if("version".equals(nodeName)){
version.append(ch,start,length);
}
}
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
//super.endDocument();
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// TODO Auto-generated method stub
//super.endElement(uri, localName, qName);
if("app".equals(localName)){
Log.d("ContentHandler", "id is "+id.toString().trim());
Log.d("ContentHandler", "name is "+name.toString().trim());
Log.d("ContentHandler", "version is "+version.toString().trim());
//最后要将StringBuilder清空掉
id.setLength(0);
name.setLength(0);
version.setLength(0);
//Log.d("ContentHandler", "app app app app =  "+nodeName);
}
//Log.d("ContentHandler", "endElement  ="+localName);
}
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
//super.startDocument();
id=new StringBuilder();
name=new StringBuilder();
version=new StringBuilder();
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
//super.startElement(uri, localName, qName, attributes);
nodeName = localName;//记录当前节点名
//Log.d("ContentHandler", "startElement localname= "+localName);
}

}


我们首先给id,name和version结点分别定义了一个StringBuilder对象,并在startDocument方法里对

它们进行了初始化。每当开始解析某个结点的时候,startElement方法就会得到调用,其中localName参数记录着当前

结点的名字,这里我们把它记录下来。接着在解析结点中具体内容的时候就会调用characters方法,我们会根据当前结点名进行判断,将解析出的内容添加到哪一个StringBuilder对象中。最后在endElement方法中进行判断,如果app结点已经解析完成,就打印出id,name和version的内容。需要注意的是,目前id,name和version中都可能是包括回车或换行符的,因此在我们打印之前我们还需要调用一下trim()方法,并且打印完成后还要将StringBuilder的内容清空掉,不然的话会影响下一次内容的读取。

接下来的工作就是修改MainActivity中的代码,如下所示:

package com.jack.networktest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.parsers.SAXParserFactory;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener{

public static final int SHOW_RESPONSE=0;
private Button sendRequest=null;
private TextView responseText=null;

private Handler handler=new Handler(){

@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch(msg.what){
case SHOW_RESPONSE:
String response=(String) msg.obj;
//在这里进行UI操作,将结果显示到界面上
responseText.setText(response);
break;
default:
break;
}

}

};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sendRequest=(Button) findViewById(R.id.send_request);
responseText=(TextView) findViewById(R.id.response_text);
sendRequest.setOnClickListener(this);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(v.getId()==R.id.send_request){
//sendRequestWithHttpURLConnection();
sendRequestWithHttpClient();
}

}

private void sendRequestWithHttpURLConnection(){
//开启线程来发起网络请求
new Thread(new Runnable(){

@Override
public void run() {
// TODO Auto-generated method stub
HttpURLConnection connection=null;

try {
URL url=new URL("http://www.baidu.com");
connection =(HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
InputStream in=connection.getInputStream();
//下面对获取到的输入流进行读取
BufferedReader reader=new BufferedReader(new InputStreamReader(in));
StringBuilder response=new StringBuilder();
String line;
while((line=reader.readLine())!=null){
response.append(line);
}
Message message=new Message();
message.what=SHOW_RESPONSE;
//将服务器返回的结果存放到Message中
message.obj=response.toString();
handler.sendMessage(message);

} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}finally{
if(connection!=null){
connection.disconnect();
}
}
}

}).start();

}

private void sendRequestWithHttpClient(){
new Thread(new Runnable(){

@Override
public void run() {
// TODO Auto-generated method stub
try{
HttpClient httpClient=new DefaultHttpClient() ;
//HttpGet httpGet=new HttpGet("http://www.baidu.com");
//指定访问的服务器地址是电脑本机,10.0.2.2对模拟器来说就是电脑本机的ip地址
//8080为端口号
HttpGet httpGet=new HttpGet("http://10.0.2.2:8080/get_data.xml");
HttpResponse httpResponse=httpClient.execute(httpGet);
if(httpResponse.getStatusLine().getStatusCode()==200){
//请求和响应都成功了
HttpEntity entity=httpResponse.getEntity();
String response=EntityUtils.toString(entity,"utf-8");
//调用parseXMLWithPull方法解析服务器返回的数据
//parseXMLWithPull(response);

//调用parseXMLWithSAX方法解析服务器返回的数据
parseXMLWithSAX(response);
Message message=new Message();
message.what=SHOW_RESPONSE;
//将服务器返回的结果存放到Message中
message.obj=response.toString();
handler.sendMessage(message);
}
}catch(Exception e){
e.printStackTrace();
}
}

}).start();

}

//使用Pull解析xml
private void parseXMLWithPull(String xmlData){
//Log.d("MainActivity", "parseXMLWithPull(String xmlData)");
try{
//获取到XmlPullParserFactory的实例,并借助这个实例得到XmlPullParser对象
XmlPullParserFactory factory=XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser=factory.newPullParser();
//调用XmlPullParser的setInput方法将服务器返回的xml数据设置进去开始解析
xmlPullParser.setInput(new StringReader(xmlData));
//通过getEventType()方法得到当前解析事件
int eventType=xmlPullParser.getEventType();
String id="";
String name="";
String version="";
while(eventType!=XmlPullParser.END_DOCUMENT){
//通过getName()方法得到当前节点的名字,如果发现节点名等于id、name、或version
//就调用nextText()方法来获取结点具体的内容,每当解析完一个app结点就将获取到的内容打印出来
String nodeName=xmlPullParser.getName();
//Log.d("MainActivity",""+eventType+ " nodeName= "+nodeName);
switch(eventType){
//开始解析某个节点
case XmlPullParser.START_TAG:{
if("id".equals(nodeName)){
id=xmlPullParser.nextText();
}else if("name".equals(nodeName)){
name=xmlPullParser.nextText();
}else if("version".equals(nodeName)){
version=xmlPullParser.nextText();
}
break;
}
case XmlPullParser.END_TAG:{
if("app".equals(nodeName)){
Log.d("MainActivity", "id is "+id);
Log.d("MainActivity", "name is "+name);
Log.d("MainActivity", "version is "+version);
}
break;
}
default:
break;
}
//调用next()方法获取到下一个解析事件
eventType=xmlPullParser.next();
}
}catch(Exception e){
e.printStackTrace();
}
}

//进行SAX解析的函数
private void parseXMLWithSAX(String xmlData){
/*
* parseXMLWithSAX方法中先创建一个SAXParserFactory的对象,然后再获取到
* XMLReader对象,接着将我们编写的ContentHandler的实例设置到XMLReader中,
* 最后调用parse()方法开始执行解析。
* */
try{
SAXParserFactory factory=SAXParserFactory.newInstance();
XMLReader xmlReader=factory.newSAXParser().getXMLReader();
ContentHandler handler=new ContentHandler();
//将ContentHandler的实例设置到XMLReader中
xmlReader.setContentHandler(handler);
//开始执行解析
xmlReader.parse(new InputSource(new StringReader(xmlData)));

}catch(Exception e){
e.printStackTrace();
}
}

}


现在重新运行一下程序,点击send request按钮,观察打印的日志如下所示:



到这里SAX解析xml就结束,xml还有一种dom的解析方式,也可以用来解析xml。

http://blog.csdn.net/j903829182/article/details/42499209
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android SAX xml pull