说说在 Android 中如何解析 XML

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/deniro_li/article/details/80641583

网络上传输数据有两种格式:XML 与 JSON。JSON 暂且按下不表,我们先说说如何解析 XML。

1 搭建 Web 服务器

假设我们使用 Apache HTTP Server 搭建好了 Web 服务器(搭建过程请看 这里)。

我们在 “Apache HTTP Server 安装目录/htdocs” 下,放置一个 XML 文件,文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>  

<China>  
  <province id="01" name="北京">  
    <city id="0101" name="北京">  
      <county id="010101" name="北京" weatherCode="101010100"/>  
      <county id="010102" name="海淀" weatherCode="101010200"/>  
      <county id="010103" name="朝阳" weatherCode="101010300"/>  
      <county id="010104" name="顺义" weatherCode="101010400"/>  
      <county id="010105" name="怀柔" weatherCode="101010500"/>  
      <county id="010106" name="通州" weatherCode="101010600"/>  
      <county id="010107" name="昌平" weatherCode="101010700"/>  
      <county id="010108" name="延庆" weatherCode="101010800"/>  
      <county id="010109" name="丰台" weatherCode="101010900"/>  
      <county id="010110" name="石景山" weatherCode="101011000"/>  
      <county id="010111" name="大兴" weatherCode="101011100"/>  
      <county id="010112" name="房山" weatherCode="101011200"/>  
      <county id="010113" name="密云" weatherCode="101011300"/>  
      <county id="010114" name="门头沟" weatherCode="101011400"/>  
      <county id="010115" name="平谷" weatherCode="101011500"/>  
    </city>  
  </province>  
</China>

在浏览器中输入 http://127.0.0.1/data.xml

这样就说明 XML 已经成功部署在服务器上咯O(∩_∩)O哈哈~

2 Pull 解析方式

private void sendByOKHttp() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                OkHttpClient client = new OkHttpClient();
                String url = "http://10.0.2.2/data.xml";
                Request request = new Request.Builder().url(url).build();
                try {
                    Response response = client.newCall(request).execute();//发送请求
                    String result = response.body().string();
                    Log.d(TAG, "result: " + result);
                    parseXMLWithPull(result);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

这里我们使用 OkHttp 来提交请求。

注意:因为这里用的是 Android 模拟器,而模拟器本身的 IP 是 127.0.0.1,所以在此不能直接使用,否则会抛出 java.net.ConnectException: Connection refused 异常。我们可以采用 IP 地址 10.0.2.2,它指向的就是本地开发环境。

使用 Pull 方式解析 XML:

private void parseXMLWithPull(String result) {
    try {
        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
        XmlPullParser parser = factory.newPullParser();
        parser.setInput(new StringReader(result));

        String id = "";
        String name = "";

        int eventType = parser.getEventType();
        while (eventType != XmlPullParser.END_DOCUMENT) {
            String nodeName = parser.getName();
            Log.d(TAG, "nodeName: "+nodeName);
            switch (eventType) {
                case XmlPullParser.START_TAG://开始解析
                    if ("county".equals(nodeName)) {
                        id = parser.getAttributeValue(null, "id");
                        name = parser.getAttributeValue(null, "name");
                    }
                    break;

                case XmlPullParser.END_TAG://完成解析
                    if ("county".equals(nodeName)) {
                        Log.i(TAG, "id : " + id);
                        Log.i(TAG, "name: " + name);
                    }
                    break;
                default:
                    break;
            }
            eventType=parser.next();
        }
    } catch (XmlPullParserException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

在此,我们首先解析 XML 文件,然后把解析得到的数据,打印出来:

3 SAX 解析方式

SAX 解析方式比 Pull 方式要复杂些,但在语义方面会更清楚。

用 SAX 解析需要实现一个继承自 DefaultHandler 的类,并重写父类的 5 个方法。

方法 说明
startDocument() 在文档开头时,会调用此方法。一般在此做一些预处理的工作。
startElement(String namespaceURI, String localName, String qName, Attributes attributes) 当读取一个开始标签时,会调用此方法。namespaceURI 是命名空间;localName 是不带命名空间前缀的标签名;qName 是带命名空间前缀的标签名; attributes 可以得到所有的属性名和相应的值 。
characters(char[] ch, int start, int length) 这个方法用来处理在 XML 文件中读取到的元素内容。ch 用于存放文件的内容,start 与 length 是读取到的字符串在这个数组中的起始位置和长度,使用 new String(ch,start,length) 就可以获取内容 。
endElement(String uri, String localName, String name) startElement() 方法相对应,解析到结束标签时,会调用该方法。
endDocument() startDocument()方法相对应。当文档解析结束时,会调用该方法,可以在此做一些善后工作。

注意: SAX 是流式处理,即当遇到一个标签时,它并不会纪录下以前所碰到的标签,也就是说,在 startElement() 方法中,所知的只是标签的名字和属性,关于标签的嵌套结构、上层标签,是否有子元素等其它与结构相关的信息并没有记录下来 。 这使得 SAX 在编程处理上没有 DOM 来得方便 。

实现自定义类型解析器:

public class CustomContentHandler extends DefaultHandler {

    private static final String TAG = "CustomContentHandler";

    List<String> ids;
    List<String> names;

    @Override
    public void startDocument() throws SAXException {
        ids = new ArrayList<>();
        names = new ArrayList<>();
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if ("county".equals(localName)) {
            ids.add(attributes.getValue("id"));
            names.add(attributes.getValue("name"));
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
    }


    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
    }

    @Override
    public void endDocument() throws SAXException {
        Log.i(TAG, "ids : " + ids);
        Log.i(TAG, "names: " + names);
    }
}

使用 SAX 方式解析 XML:

private void parseXMLWithSAX(String result) {
    try {
        SAXParserFactory factory=SAXParserFactory.newInstance();
        XMLReader reader=factory.newSAXParser().getXMLReader();
        reader.setContentHandler(new CustomContentHandler());
        reader.parse(new InputSource(new StringReader(result)));
    } catch (SAXException e) {
        e.printStackTrace();
    } catch (ParserConfigurationException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

输入结果:

展开阅读全文

Android xml解析

06-02

[code=Java]rnpackage com.wyt.MP3player;rnrnimport java.io.StringReader;rnimport java.util.ArrayList;rnimport java.util.Iterator;rnimport java.util.List;rnrnimport javax.xml.parsers.SAXParserFactory;rnrnimport org.xml.sax.InputSource;rnimport org.xml.sax.XMLReader;rnrnimport android.app.ListActivity;rnimport android.os.Bundle;rnimport android.view.Menu;rnimport android.view.MenuItem;rnrnimport com.wyt.download.HttpDownloader;rnimport com.wyt.model.MP3info;rnimport com.wyt.xml.Mp3ListContentHandler;rnrnpublic class MP3ListActivity extends ListActivity rnrn //创建常量rn private static final int UPDATE = 1;rn private static final int ABOUT = 2;rnrn //点击menu后会调用该方法,在此方法中添加需要的控件rn @Overridern public boolean onCreateOptionsMenu(Menu menu) rn // TODO Auto-generated method stubrnrn //添加按钮(更新,关于)rn menu.add(0, UPDATE, 1, R.string.mp3List_update);rn menu.add(0, ABOUT, 2, R.string.mp3List_about);rnrn return super.onCreateOptionsMenu(menu);rn rnrn /** Called when the activity is first created. */rn @Overridern public void onCreate(Bundle savedInstanceState) rn super.onCreate(savedInstanceState);rn setContentView(R.layout.main);rn rnrn //当点击任意一个按钮时显示的列表rn @Overridern public boolean onOptionsItemSelected(MenuItem item) rn //判断得到的按钮号,并做出相应的动作rn //点击的是更新按钮rn if (item.getItemId() == UPDATE) rnrn //传入本机的地址rn String xml = downloadXML("http://10.10.16.97:8080/MP3/resources.xml");rn System.out.println("!!!!!!!!!!!1");rn parseXml(xml);rn System.out.println("########");rn //点击的是关于按钮rn else if (item.getItemId() == ABOUT) rnrn rn return super.onOptionsItemSelected(item);rn rnrn //调用下载类rn private String downloadXML(String urlStr) rn //创建Download对象rn HttpDownloader download = new HttpDownloader();rn //得到本机的URL地址rn String result = download.download(urlStr);rnrn return result;rn rnrn //解析xml文件rn private List parseXml(String xmlStr) rn // 创建一个新的字符串rn StringReader read = new StringReader(xmlStr);rn // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入rn InputSource source = new InputSource(read);rnrn try rn //创建xml解析器rn SAXParserFactory sax = SAXParserFactory.newInstance();rn// SAXParser sp = sax.newSAXParser();rn// XMLReader xr = sp.getXMLReader();rn XMLReader xmlReader = sax.newSAXParser().getXMLReader();rn rn List info = new ArrayList();rn Mp3ListContentHandler mp3ListContentHandler = new Mp3ListContentHandler(rn info);rn //为xmlread设置内容处理器rn xmlReader.setContentHandler(mp3ListContentHandler);rn rn //开始解析文件rn xmlReader.parse(source);rn //parse(new InputSource(new StringReader(xmlStr)));rn System.out.println("@@@@@@@@@@@@@@@@@@@@2");rn //循环输出解析内容rn for (Iterator iterator = info.iterator(); iterator.hasNext();) rn MP3info mp3info = (MP3info) iterator.next();rn System.out.println("***"+mp3info);rn rn catch (Exception e) rn e.printStackTrace();rn rn return null;rn rnrnrnrnrnrnpackage com.wyt.xml;rnrnimport java.util.List;rnrnimport org.xml.sax.Attributes;rnimport org.xml.sax.SAXException;rnimport org.xml.sax.helpers.DefaultHandler;rnrnimport com.wyt.model.MP3info;rnrnpublic class Mp3ListContentHandler extends DefaultHandlerrnrn private List info=null;rn private MP3info mp3info=null;rn private String tagName=null;rn rn public Mp3ListContentHandler(List info) rn super();rn this.info = info;rn rnrn public List getInfo() rn return info;rn rnrn public void setInfo(List info) rn this.info = info;rn rnrn //在xml文件中,若遇到某个指定标签就将该文件内容写入到MP3info中rn @Overridern public void characters(char[] ch, int start, int length)rn throws SAXException rn String temp=new String(ch,start,length);rn if(tagName.equals("id"))rn mp3info.setId(temp);rn else if(tagName.equals("mp3_name"))rn mp3info.setMp3Name(temp);rn else if(tagName.equals("mp3_size"))rn mp3info.setMp3Size(temp);rn else if(tagName.equals("lrc_name"))rn mp3info.setLrcName(temp);rn else if(tagName.equals("lrc_size"))rn mp3info.setLrcSize(temp);rn rn rnrn @Overridern public void endDocument() throws SAXException rn rn rn //在结束时,将在xml中读到的数据放到List中rn @Overridern public void endElement(String uri, String localName, String name)rn throws SAXException rn if(name.equals("resource"))rn info.add(mp3info);rn rn System.out.println("%%%%%%%%%%%%"); rn tagName=""; rn rnrn @Overridern public void startDocument() throws SAXException rn // TODO Auto-generated method stubrn super.startDocument();rn rnrn //在开始的时候,一遇到resource就生成MP3info对象rn @Overridern public void startElement(String uri, String localName, String name,rn Attributes attributes) throws SAXException rn this.tagName=localName;rn rn //遇到"resource"就生成一个MP3info对象rn if(tagName.equals("resource"))rn mp3info=new MP3info();rn rn rnrnrnrnrn警告:rn06-02 13:17:16.006: WARN/KeyCharacterMap(889): No keyboard for id 0rn06-02 13:17:16.006: WARN/KeyCharacterMap(889): Using default keymap: /system/usr/keychars/qwerty.kcm.binrn06-02 13:17:17.045: INFO/global(889): Default buffer size used in BufferedReader constructor. It would be better to be explicit if an 8k-char buffer is required.rn06-02 13:17:17.074: WARN/System.err(889): org.apache.harmony.xml.ExpatParser$ParseException: At line 1, column 104: mismatched tagrn06-02 13:17:17.086: WARN/System.err(889): at org.apache.harmony.xml.ExpatParser.parseFragment(ExpatParser.java:507)rn06-02 13:17:17.086: WARN/System.err(889): at org.apache.harmony.xml.ExpatParser.parseDocument(ExpatParser.java:492)rn06-02 13:17:17.094: WARN/System.err(889): at org.apache.harmony.xml.ExpatReader.parse(ExpatReader.java:308)rn06-02 13:17:17.094: WARN/System.err(889): at org.apache.harmony.xml.ExpatReader.parse(ExpatReader.java:264)rn06-02 13:17:17.105: WARN/System.err(889): at com.wyt.MP3player.MP3ListActivity.parseXml(MP3ListActivity.java:97)rn06-02 13:17:17.114: WARN/System.err(889): at com.wyt.MP3player.MP3ListActivity.onOptionsItemSelected(MP3ListActivity.java:57)rn06-02 13:17:17.114: WARN/System.err(889): at android.app.Activity.onMenuItemSelected(Activity.java:2195)rn06-02 13:17:17.114: WARN/System.err(889): at com.android.internal.policy.impl.PhoneWindow.onMenuItemSelected(PhoneWindow.java:730)rn06-02 13:17:17.114: WARN/System.err(889): at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:143)rn06-02 13:17:17.126: WARN/System.err(889): at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:855)rn06-02 13:17:17.126: WARN/System.err(889): at com.android.internal.view.menu.IconMenuView.invokeItem(IconMenuView.java:532)rn06-02 13:17:17.126: WARN/System.err(889): at com.android.internal.view.menu.IconMenuItemView.performClick(IconMenuItemView.java:122)rn06-02 13:17:17.135: WARN/System.err(889): at android.view.View$PerformClick.run(View.java:8816)rn06-02 13:17:17.135: WARN/System.err(889): at android.os.Handler.handleCallback(Handler.java:587)rn06-02 13:17:17.145: WARN/System.err(889): at android.os.Handler.dispatchMessage(Handler.java:92)rn06-02 13:17:17.145: WARN/System.err(889): at android.os.Looper.loop(Looper.java:123)rn06-02 13:17:17.154: WARN/System.err(889): at android.app.ActivityThread.main(ActivityThread.java:4627)rn06-02 13:17:17.154: WARN/System.err(889): at java.lang.reflect.Method.invokeNative(Native Method)rn06-02 13:17:17.166: WARN/System.err(889): at java.lang.reflect.Method.invoke(Method.java:521)rn06-02 13:17:17.166: WARN/System.err(889): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)rn06-02 13:17:17.166: WARN/System.err(889): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)rn06-02 13:17:17.176: WARN/System.err(889): at dalvik.system.NativeStart.main(Native Method)rn06-02 13:17:17.256: WARN/InputManagerService(59): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@4504a6d8rnrnrn[/code] 论坛

没有更多推荐了,返回首页