android学习二十二(使用SAX解析xml)
上一篇博客是使用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
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。