Android 网络传输数据之解析XML格式数据(Pull&SAX)

Android 网络传输数据之解析XML格式数据

每个访问网络的应用程序都会有一个自己的服务器,我们可以向服务器提交数据也可以从服务器上获取数据。下面我们就介绍下网络上传输数据最常用的一种格式XML数据格式。

在开始之前需要搭建一个web服务器(具体操作可以参考:https://blog.csdn.net/vagabond_/article/details/90436858),
在\Apache\htdcos目录下新建一个名为get_data.xml的文件,然后编辑内容如下:
在这里插入图片描述
在浏览器中访问 http://127.0.0.1:8023/get_data.xml 会出现下图所示的网页:
在这里插入图片描述
下面介绍两种常用的两种解析xml格式的数据方式

Pull解析方式

首先创建一个空的Activity,做一个简单的布局,布局代码如下 :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
      android:id="@+id/send_request"
      android:layout_height="wrap_content"
      android:layout_width="match_parent"
      android:text="Send Request"/>
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">
     <TextView
         android:id="@+id/response_text"
         android:layout_width="match_parent"
         android:layout_height="wrap_content" />

    </ScrollView>
</LinearLayout>

重点在MainActivity,下面给出代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    TextView responseText;

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

    @Override
    public void onClick(View v) {

        if(v.getId() == R.id.send_request){

            sendRequestWithOjHttp();
        }
    }
    private void sendRequestWithOjHttp(){
        //开启线程来发起网络请求
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                BufferedReader reader = null;

                try{
                    OkHttpClient client = new OkHttpClient();
                    Request request = new Request.Builder()
                            .url("http://10.0.2.2:8023/get_data.xml")
                            .build();
                    Response response = client.newCall(request).execute();
                    String responseData = response.body().string();
                    paraseXMLWithPull(responseData);

                }catch (Exception e){

                    e.printStackTrace();
                }
            }
        }).start();
    }
    private void paraseXMLWithPull(String xmlData){
       try{
           XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
           XmlPullParser xmlPullParser = factory.newPullParser();
           xmlPullParser.setInput(new StringReader(xmlData));
           int evenType = xmlPullParser.getEventType();
           String id="";
           String name="";
           String version="";
           while(evenType != XmlPullParser.END_DOCUMENT){
               String nodeName = xmlPullParser.getName();
               switch(evenType){
                   //开始解析某个节点
                   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;
               }
               evenType = xmlPullParser.next();
           }
       }catch (Exception e){
           e.printStackTrace();
       }

    }
}

创建request对象发送请求,通过url()方法来设置目标网络地址,这里将HTTP请求的地址改成 http://10.0.0.2:8023/get_data.xml, 10.0.0.2对于模拟器来说就是电脑本机的IP地址。调用OkHttpClient的newCall()方法来创建一个Call对象,并调用它的execute()方法来发送请求并获取服务器数据。得到服务器返回的数据之后,调用parseXMLWithPull()方法来解析服务器返回的数据。

在parseXMLWithPull()中,首先获取一个XmlPullParserFactory的实例,并借助该实例得到XmlPullParser对象,然后调用XmlPullParser的setInput()方法将服务器返回的XML数据设置进去。之后开始解析,通过getEvenType()可以得到当前的解析事件,然后在一个while循环中不断的进行地解析,如果当前的解析事件不等于XmlPullParser.END_DOCUMENT,说明解析工作还没完成,调用next()方法后可以获取下个解析事件。

在while循环中,通过getName()方法得到当前节点的名字,如果发现节点等于id、name或version,就调用nextText()方法来获取节点内具体的内容,每当解析完一个app节点后就获取到的内容就打印出现。

点击send Request按钮

在Logcat中打印的日志如下,可以看到已经将XML数据中的制定内容成功解析出来了。
在这里插入图片描述

SAX解析方式

相对于Pull解析要复杂一些,但是在语义上更容易理解。

在上面的程序进行修改即可,新建一个ContentHandlder类并继承自DefaultHandler,重写父类的5个方法

public class ContentHandler extends DefaultHandler {
    private String nodeName;
    private StringBuilder id;
    private StringBuilder name;
    private StringBuilder version;

    @Override
    public void startDocument() throws SAXException {
        id = new StringBuilder();
        name = new StringBuilder();
        version = new StringBuilder();
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        nodeName = localName;
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        if("id".equals(nodeName)){
            id.append(ch,start,length);
        }else if("name".equals(nodeName)){
            name.append(ch,start,length);
        }else if("version".equals((nodeName))){
            version.append(ch,start,length);
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if("app".equals(localName)){
            Log.d("ContentHandle","id is "+id.toString().trim());
            Log.d("ContentHandle","name is "+name.toString().trim());
            Log.d("ContentHandle","version is "+version.toString().trim());
            //最后要将StringBuilder清空掉
            id.setLength(0);
            name.setLength(0);
            version.setLength(0);
        }
    }

    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }
}

startDocument()方法会在开始XML解析的时候调用,startElement()方法会在开始解析某个节点的时候调用,characters()方法会在获取节点中内容时调用,endElement()方法会在完成解析某个节点的时候调用,endDocument()方法会在完成整个XML解析的时候调用。

首先给id、name、version节点分别定义了一个StringBuilder对象,并在startDocument()方法中对它们进行初始化。在开始解析某个节点的时候会调用startElement()方法(localName参数记录当前节点的名字),在解析节点的具体内容时会调用characters()方法,我们会根据当前的节点名进行判断,将解析的内容添加到StringBuilder对象中,最后在endElement()方法中进行判断,如果app节点已经完成解析,就打印内容并在打印完成后清空StringBuilder。

修改MainActivity:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    TextView responseText;

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

    @Override
    public void onClick(View v) {

        if(v.getId() == R.id.send_request){

            sendRequestWithOkHttp();
        }
    }
    private void sendRequestWithOkHttp(){
        //开启线程来发起网络请求
        new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    OkHttpClient client = new OkHttpClient();

                    Request request = new Request.Builder()
                            .url("http://10.0.2.2:8023/get_data.xml")
                            .build();
                    Response response = client.newCall(request).execute();
             
                    String responseData = response.body().string();
                   
                    paraseXMLWithSAX(responseData);
              
                }catch (Exception e){

                    e.printStackTrace();
                }
            }
        }).start();
    }
    private void paraseXMLWithSAX(String xmlData){
       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();
       }
    }
}

在得到服务器的返回数据后,调用paraseXMLWithSAX()方法来解析XML数据。在该方法中创建了一个SAXParserFactory的对象,在获取到XMLReader对象,之后将ContentHandler的实例设置到XMLReader中,调用parse()方法解析。

在这里插入图片描述
参考《第一行代码》

(喜欢的朋友可以点个关注 )

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值