Android 經過Dom, Sax, Pull解析網絡xml數據

這篇文章不是徹底原創,XML解析的部分參考了 liuhe688 的文章。文章地址:http://blog.csdn.net/liuhe688/article/details/6415593html

這是一個幾乎完整的過程。覆蓋面也比較廣。應用了AsyncTask, BaseAdapter, ListView, Dom, Sax, Pull等,這些也是開發應用中必不可少的部分。java

效果圖:node

    

首先,作了些準備工做。down了一份xml數據放在本地服務器上android

定義了一個model。apache

book.java數組

package com.example.phonedemo.model;

public class Book {
    private int id;
    private String name;
    private float price;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

}

一、客戶端發起請求,服務器

這是經過AsyncTask異步發起的請求。網絡

AsyncTask 主要須要複寫四個方法:app

onProExecute():這個方法會在UI線程中調用 execute(..)以後當即執行,在開發中一般作一些初始化和加載UI顯示的工做。dom

doInBackground(String... params):比較費時的操做,能夠放在這裏。網絡請求等...

onProgressUpdate(Integer... values):一般,咱們在耗時操做時候,好比download,會有一個百分比進度。在doInBackground()方法中調用

publishProgress()方法後,系統會調用此方法,更新進度信息。

onPostExecute(InputStream result):執行完畢之後調用的方法。

二、服務器端返回xml數據,

三、客戶端解析數據,最終呈現出來

我用了三種解析方法,參照上述blog的地址。不過,在他得代碼中稍有問題。ID是沒有的。我在個人代碼中改正了。

三種方式都是解析一個xml,因此寫了一個接口文件。

BookParserImpl.java

package com.example.phonedemo.util;

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

import com.example.phonedemo.model.Book;


public interface BookParserImpl {
    public List<Book> parse(InputStream is);
    
    public String serialize(List<Book> books);
}

而後,三種解析分別實現它便可。

Dom解析方式

優勢:功能齊全,強大。缺點:由於須要徹底加載文檔,致使,比較耗資源。前輩說j2ee中用的較多。

我雖然也學Java,可是一直都與前臺打交道。曾經學的東西,工做中不用,就全忘了。罪過,罪過...

 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
 DocumentBuilder builder = factory.newDocumentBuilder();
 Document doc = builder.parser(InputStream input);

上述dom初始化解析實例的代碼。

DomBookParser.java

package com.example.phonedemo.util;

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

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.example.phonedemo.model.Book;

public class DomBookParser implements BookParserImpl {

    @Override
    public List<Book> parse(InputStream is) {
        List<Book> list = new ArrayList<Book>();
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = null;
        Document doc = null;
        try {
            builder = factory.newDocumentBuilder();
            doc = builder.parse(is);
            NodeList itemList = doc.getDocumentElement().getElementsByTagName(
                    "book");
            for (int i = 0; i < itemList.getLength(); i++) {
                Book book = new Book();
                Node node = itemList.item(i);
                NodeList child = node.getChildNodes();
                NamedNodeMap attr = node.getAttributes();
                book.setId(Integer.parseInt(attr.getNamedItem("id")
                        .getNodeValue()));
                for (int j = 0; j < child.getLength(); j++) {
                    Node childItem = child.item(j);
                    String nodeName = childItem.getNodeName();
                    if (nodeName.equals("name")) {
                        book.setName(childItem.getFirstChild().getNodeValue());
                    } else if (nodeName.equals("price")) {
                        book.setPrice(Float.parseFloat(childItem
                                .getFirstChild().getNodeValue()));
                    }
                }

                list.add(book);
            }

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return list;
    }

    @Override
    public String serialize(List<Book> books) {
        // TODO Auto-generated method stub
        return null;
    }
}

Sax解析方式

sax是事件驅動型的,比起dom來更加靈巧。也更加簡單快速。

SaxBookParser.java

package com.example.phonedemo.util;

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

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

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

import com.example.phonedemo.model.Book;

public class SaxBookParser implements BookParserImpl {

    @Override
    public List<Book> parse(InputStream is) {
        // TODO Auto-generated method stub
        SAXParserFactory factory = SAXParserFactory.newInstance();
        MyHandler handler = null;
        try {
            SAXParser parser = factory.newSAXParser();
            handler = new MyHandler();
            parser.parse(is, handler);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return handler.getBooks();
    }

    /**
     * <b>解析xml的輔助類</b><br />
     * <b>startDocument()</b> 當遇到文檔的開頭的時候,調用這個方法,能夠在其中作一些預處理的工做。<br />
     * <b>endDocument()</b> 和上面的方法相對應,當文檔結束的時候,調用這個方法,能夠在其中作一些善後的工做。 <br/>
     * <b>startElement(String namespaceURI, String localName, String qName,
     * Attributes atts)</b>當讀到一個開始標籤的時候,會觸發這個方法。<br />
     * <b>endElement(String uri, String localName, String name)</b>
     * 這個方法和上面的方法相對應,在遇到結束標籤的時候,調用這個方法。<br />
     * <b>characters(char[] ch, int start, int length)</b>
     * 這個方法用來處理在XML文件中讀到的內容,第一個參數用於存放文件的內容,<br />
     * 後面兩個參數是讀到的字符串在這個數組中的起始位置和長度,使用new String(ch,start,length)就能夠獲取內容。
     * 
     * @author qxj
     * 
     */
    class MyHandler extends DefaultHandler {

        private List<Book> books;
        private Book book;
        private StringBuilder builder;

        public List<Book> getBooks() {
            return books;
        }

        /**
         * 接收元素中字符數據的通知。
         * 
         * @param ch
         *            - 字符。
         * @param start
         *            - 字符數組中的開始位置。
         * @param length
         *            - 從字符數組中使用的字符數。
         */
        @Override
        public void characters(char[] ch, int start, int length)
                throws SAXException {
            // TODO Auto-generated method stub
            super.characters(ch, start, length);
            builder.append(ch, start, length);
        }

        /**
         * 接收元素結束的通知
         * 
         * @param uri
         *            - 名稱空間 URI,若是元素沒有任何名稱空間 URI,或者沒有正在執行名稱空間處理,則爲空字符串。
         * @param localName
         *            - 本地名稱(不帶前綴),若是沒有正在執行名稱空間處理,則爲空字符串。
         * @param qName
         *            - 限定的名稱(帶有前綴),若是限定的名稱不可用,則爲空字符串。
         * @exception SAXException
         *                - 任何 SAX 異常,可能包裝另外的異常。
         */
        @Override
        public void endElement(String uri, String localName, String qName)
                throws SAXException {
            // TODO Auto-generated method stub
            super.endElement(uri, localName, qName);
            if (localName.equals("book")) {
                books.add(book);
            } else if (localName.equals("name")) {
                book.setName(builder.toString());
            } else if (localName.equals("price")) {
                book.setPrice(Float.parseFloat(builder.toString()));
            }
        }

        /**
         * 接收文檔的開始的通知
         * 
         * @exception - SAXException - 任何 SAX 異常,可能包裝另外的異常
         */
        @Override
        public void startDocument() throws SAXException {
            // TODO Auto-generated method stub
            super.startDocument();
            books = new ArrayList<Book>();
            builder = new StringBuilder();
        }

        /**
         * 接收元素開始的通知。
         * 
         * @param uri
         *            - 名稱空間 URI,若是元素沒有任何名稱空間 URI,或者沒有正在執行名稱空間處理,則爲空字符串。
         * @param localName
         *            - 本地名稱(不帶前綴),若是沒有正在執行名稱空間處理,則爲空字符串。
         * @param qName
         *            - 限定的名稱(帶有前綴),若是限定的名稱不可用,則爲空字符串。
         * @param attributes
         *            - 附加到元素的屬性。若是沒有屬性,則它將是空的 Attributes 對象。
         * @exception SAXException
         *                - 任何 SAX 異常,可能包裝另外的異常
         */
        @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);
            if (localName.equals("book")) {
                book = new Book();
                if (attributes != null) {
                    book.setId(Integer.parseInt(attributes.getValue("id")));
                }
            }
            builder.setLength(0);
        }

    }

    @Override
    public String serialize(List<Book> books) {
        // TODO Auto-generated method stub
        return null;
    }

}

Pull解析方式

我最喜歡這種解析方式,它最輕巧,簡便。android 用到了不少xml的文件,系統都是用pull來解析的。從這個層面中能夠看出來。android建議使用這種解析方式。

PullBookParser.java

package com.example.phonedemo.util;

import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;

import android.util.Xml;

import com.example.phonedemo.model.Book;

public class PullBookParser implements BookParserImpl {

    @Override
    public List<Book> parse(InputStream is) {
        // TODO Auto-generated method stub
        List<Book> books = null;
        Book book = null;

        XmlPullParser parser = Xml.newPullParser();
        try {
            parser.setInput(is, "UTF-8");
            int eventType = parser.getEventType();
            while (eventType != XmlPullParser.END_DOCUMENT) {
                switch (eventType) {
                case XmlPullParser.START_DOCUMENT:
                    books = new ArrayList<Book>();
                    break;
                case XmlPullParser.START_TAG:
                    if (parser.getName().equals("book")) {
                        book = new Book();
                        book.setId(Integer.parseInt(parser.getAttributeValue(0)));
                    } else if (parser.getName().equals("name")) {
                        parser.next();
                        book.setName(parser.getText());
                    } else if (parser.getName().equals("price")) {
                        parser.next();
                        book.setPrice(Float.parseFloat(parser.getText()));
                    }
                    break;
                case XmlPullParser.END_TAG:
                    if (parser.getName().endsWith("book")) {
                        books.add(book);
                        book = null;
                    }
                    break;
                }
                parser.next();
                eventType = parser.getEventType();
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return books;
    }

    @Override
    public String serialize(List<Book> books) {
        // TODO Auto-generated method stub
        XmlSerializer serializer = Xml.newSerializer();
        StringWriter writer = new StringWriter();
        try {
            serializer.setOutput(writer);
            serializer.startDocument("UTF-8", true);
            serializer.startTag("", "books");
            for (Book book : books) {
                serializer.startTag("", "book");
                serializer.attribute("", "id", String.valueOf(book.getId()));

                serializer.startTag("", "name");
                serializer.text(book.getName());
                serializer.endTag("", "name");

                serializer.startTag("", "price");
                serializer.text(book.getPrice() + "");
                serializer.endTag("", "price");
                serializer.endTag("", "book");
            }
            serializer.endTag("", "books");
            serializer.endDocument();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("doc: " + writer.toString());
        return writer.toString();
    }
}

最後,附上Activity

package com.example.phonedemo;

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

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.example.phonedemo.model.Book;
import com.example.phonedemo.util.DomBookParser;
import com.example.phonedemo.util.PullBookParser;
import com.example.phonedemo.util.SaxBookParser;

public class XMLParserDemo extends Activity {

    private static final String TAG = "XMLParserDemo";

    private static final String PATH = "http://192.168.1.121:8080/wwwroot/android/book.html";

    private List<Book> list = null;
    private Button dom = null;
    private Button sax = null;
    private Button pull = null;
    private Button clear = null;
    private TextView parser = null;
    private ListView listView = null;

    /**
     * 異步請求數據
     * 
     * @author qinxijuan
     * 
     */
    private class MyAsyncTask extends AsyncTask<String, Integer, InputStream> {

        // 表示當前使用哪種解析方式,0:dom ; 1: sax; 2:pull
        private int flag = 0;

        public MyAsyncTask(int flag) {
            this.flag = flag;
        }

        @Override
        protected void onPostExecute(InputStream result) {
            if (result != null) {
                if (flag == 0) {
                    domParserFromInputStream(result);
                } else if (flag == 1) {
                    saxParserFromInputStream(result);
                } else if (flag == 2) {
                    pullParserFromInputStream(result);
                }
            } else {
                Toast.makeText(XMLParserDemo.this, "數據獲取失敗!",
                        Toast.LENGTH_SHORT).show();
            }
        }

        @Override
        protected void onPreExecute() {
            Log.i(TAG, "onPreExecute() Loading ... ");
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            // TODO Auto-generated method stub
            super.onProgressUpdate(values);
        }

        @Override
        protected InputStream doInBackground(String... params) {

            InputStream result = null;
            HttpClient client = new DefaultHttpClient();
            HttpGet get = new HttpGet(params[0]);
            HttpResponse response = null;
            try {
                response = client.execute(get);
                if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                    HttpEntity entity = response.getEntity();
                    result = entity.getContent();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            return result;
        }

    }

    static class ViewHolder {
        TextView id;
        TextView name;
        TextView price;
    }

    class MyBaseAdapter extends BaseAdapter {

        private List<Book> list = null;
        private LayoutInflater ly = null;

        public MyBaseAdapter(Context context, List<Book> list) {
            this.ly = LayoutInflater.from(context);
            this.list = list;
        }

        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return this.list.size();
        }

        @Override
        public Object getItem(int arg0) {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public long getItemId(int arg0) {
            // TODO Auto-generated method stub
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup arg2) {
            ViewHolder viewHolder = null;
            if (convertView == null) {
                viewHolder = new ViewHolder();
                convertView = ly.inflate(R.layout.simpleitem, null);
                viewHolder.id = (TextView) convertView.findViewById(R.id.id);
                viewHolder.name = (TextView) convertView
                        .findViewById(R.id.name);
                viewHolder.price = (TextView) convertView
                        .findViewById(R.id.age);
                convertView.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) convertView.getTag();
            }
            viewHolder.id.setText(String.valueOf(list.get(position).getId()));
            viewHolder.name.setText(list.get(position).getName());
            viewHolder.price.setText(String.valueOf(list.get(position)
                    .getPrice()));
            return convertView;
        }

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        super.setContentView(R.layout.xml_parser_layout);

        this.dom = (Button) super.findViewById(R.id.dom);
        this.sax = (Button) super.findViewById(R.id.sax);
        this.pull = (Button) super.findViewById(R.id.pull);
        this.clear = (Button) super.findViewById(R.id.clear);
        this.parser = (TextView) super.findViewById(R.id.parser);
        this.listView = (ListView) super.findViewById(R.id.list_view);

        this.clear.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                list = new ArrayList<Book>();
                MyBaseAdapter adapter = new MyBaseAdapter(XMLParserDemo.this,
                        list);
                listView.setAdapter(adapter);
                parser.setText("數據清除完畢");
            }
        });

        this.dom.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                MyAsyncTask mTask = new MyAsyncTask(0);
                mTask.execute(PATH);
                parser.setText("使用dom方式解析");
            }
        });

        this.sax.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                MyAsyncTask mTask = new MyAsyncTask(1);
                mTask.execute(PATH);
                parser.setText("使用sax方式解析");
            }
        });

        this.pull.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                MyAsyncTask mTask = new MyAsyncTask(2);
                mTask.execute(PATH);
                parser.setText("使用pull方式解析");
            }
        });
    }

    public void domParserFromInputStream(InputStream input) {
        list = new ArrayList<Book>();
        DomBookParser domParser = new DomBookParser();
        System.out.println("input: " + input.toString());
        list = domParser.parse(input);
        MyBaseAdapter adapter = new MyBaseAdapter(this, list);
        this.listView.setAdapter(adapter);
    }

    public void saxParserFromInputStream(InputStream input) {
        list = new ArrayList<Book>();
        SaxBookParser saxParser = new SaxBookParser();
        list = saxParser.parse(input);
        MyBaseAdapter adapter = new MyBaseAdapter(this, list);
        this.listView.setAdapter(adapter);
    }

    public void pullParserFromInputStream(InputStream input) {
        PullBookParser pullParser = new PullBookParser();
        list = pullParser.parse(input);
        MyBaseAdapter adapter = new MyBaseAdapter(this, list);
        this.listView.setAdapter(adapter);
    }

}

xml_parser_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/dom"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Dom" />

        <Button
            android:id="@+id/sax"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Sax" />

        <Button
            android:id="@+id/pull"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="pull" />

        <Button
            android:id="@+id/clear"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="clear" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/parser"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text=" " />
    </LinearLayout>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        <ListView
            android:id="@+id/list_view"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" >
        </ListView>
    </LinearLayout>

</LinearLayout>
相關文章
相關標籤/搜索