zoukankan      html  css  js  c++  java
  • Android 通过Dom, Sax, Pull解析网络xml数据

    这篇文章不是完全原创,XML解析的部分参考了 liuhe688 的文章。文章地址:http://blog.csdn.net/liuhe688/article/details/6415593

    这是一个几乎完整的过程。覆盖面也比较广。应用了AsyncTask, BaseAdapter, ListView, Dom, Sax, Pull等,这些也是开发应用中必不可少的部分。

    效果图:

        

    首先,做了些准备工作。down了一份xml数据放在本地服务器上

    定义了一个model。

    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;
        }
    
    }

    1、客户端发起请求,

    这是通过AsyncTask异步发起的请求。

    AsyncTask 主要需要复写四个方法:

    onProExecute():这个方法会在UI线程中调用 execute(..)之后立即执行,在开发中通常做一些初始化和加载UI显示的工作。

    doInBackground(String... params):比较费时的操作,可以放在这里。网络请求等...

    onProgressUpdate(Integer... values):通常,我们在耗时操作时候,比如download,会有一个百分比进度。在doInBackground()方法中调用

    publishProgress()方法后,系统会调用此方法,更新进度信息。

    onPostExecute(InputStream result):执行完毕以后调用的方法。

    2、服务器端返回xml数据,

    3、客户端解析数据,最终呈现出来

    我用了三种解析方法,参照上述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>
  • 相关阅读:
    tip
    tip
    paper clip 使用
    这个菜单有点cool
    jqueryoptiontree plugin introduce by frederick.mao
    ruby语法不理解
    近来心得,心不可太贪,见好就收
    XPCOM的有关链接
    rails router
    rails3高端observer模式
  • 原文地址:https://www.cnblogs.com/waddell/p/3405501.html
Copyright © 2011-2022 走看看