必威体育Betway必威体育官网
当前位置:首页 > IT技术

解析 XML格式数据

时间:2019-06-20 23:45:19来源:IT技术作者:seo实验室小编阅读:71次「手机版」
 

xml格式

通常情况下,每个需要访问网络的应用程序都会有一个自己的服务器,我们可以向服务 器提交数据,也可以从服务器上获取数据

不过这个时候就出现了一个问题,这些数据到底 要以什么样的格式在网络上传输呢?

在网络上传输数据时最常用的格式有两种,XML和 JSON,今天先学习如何解析 XML格式的数据

在开始之前我们还需要先解决一个问题,就是从哪儿才能获取一段 XML 格式的数据?这里我准备教你搭建一个最简单的 Web服务器,在这个服务器上提供一段 XML文本, 然后我们在程序里去访问这个服务器,再对得到的 XML文本进行解析

1、首先配置apache服务器,可以看以下文章

Apache服务器的下载与安装

2、在htdocs目录下新建get_data.xml文件,文件内容如下

<?xml version="1.0"?>
<apps>
  <app>
    <id>1</id>
    <name>Google Maps</name>
    <version>1.0</version>
  </app>
  <app>
    <id>2</id>
    <name>Chrome</name>
    <version>2.1</version>
  </app>
  <app>
    <id>3</id>
    <name>Google Play</name>
    <version>2.3</version>
  </app>
</apps>

ps:如果想要格式化xml文件可以查看这篇文章 [EditPlus格式化XML]

http://blog.csdn.net/u011498933/article/details/53130112

3、现在访问get_data.xml时,页面如下

这里写图片描述

既然 XML格式的数据已经提供好了,现在要做的就是从中解析出我们想要得到的那部分内容

Pull解析方式

以下代码是基于

HttpURLConnection使用这篇文章进行的修改

只修改MainActivity.java代码

 private void sendRequestWithURLConnection() {
        //开启线程发起网络请求
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                try {
                    URL url = new URL("http://192.168.1.51/get_data.xml");
                    connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    InputStream inputStream = connection.getInputStream();
                    //对获取的输入流进行读取
                    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                    StringBuilder response = new StringBuilder();

                    String line;
                    while ((line = reader.readLine()) != null) {
                        response.append(line);
                    }
                    parseXMLWithPull(response.toString());

                } catch (MalformedURLException e) {

                } catch (ProtocolException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

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

            int eventType = xmlPullParser.getEventType();
            String id = "";
            String name = "";
            String version = "";

            while (eventType != XmlPullParser.END_DOCUMENT) {
                String nodeName = xmlPullParser.getName();
                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;
                }
                eventType = xmlPullParser.next();
            }
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

和之前文章相比有两处修改:

1、其中Url变成”http://192.168.1.51/get_data.xml“,http://192.168.1.51对于模拟器来说就是电脑本机的 IP地址,如何查看本机ip地址呢,可以参考以下文章

[查看电脑ip地址]

http://blog.csdn.net/u010356768/article/details/77744688

2、在得到了服务器返回的数据后,我们并不再去发 送一条消息,而是调用了 parseXMLWithPull()方法来解析服务器返回的数据

解释parseXMLWithPull()方法

首先要获取到一个 XmlPullParserFactory 的 实 例 , 并 借 助 这 个 实 例 得 到 XmlPullParser 对象,然后调用 XmlPullParser的 setInput()方法将服务器返回的 XML数据设置进去就可以开始解析了

解析的过程也是非常简单,通过getEventType()可以得到当前的解析事件,然后在一个 while循环 中不断地进行解析

如果当前的解析事件不等于 XmlPullParser.END_DOCUMENT,说明解析工作还没完成,调用 next()方法后可以获取下一个解析事件

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

观察 LogCat中的打印日志

这里写图片描述

我们已经将 XML数据中的指定内容成功解析出来了

SAX解析方式

SAX解析也是一种特别常 用的 XML解析方式,虽然它的用法比 Pull解析要复杂一些,但在语义方面会更加的清楚

通常情况下我们都会新建一个类继承自 DefaultHandler,并重写父类的五个方法,如下 所示

public class MyHandler extends DefaultHandler {
    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
    }

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

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

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

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

startDocument()方法会在开始 XML 解析的时候调用

startElement()方法会在开始解析某个结点的时候调用

characters()方法会在获取结点中内容 的时候调用

endElement()方法会在完成解析某个结点的时候调用

endDocument()方法会在 完成整个 XML解析的时候调用

其中,startElement()、characters()和 endElement()这三个方 法是有参数的,从 XML中解析出的数据就会以参数的形式传入到这些方法中。需要注意的 是,在获取结点中的内容时,characters()方法可能会被调用多次,一些换行符也被当作内容 解析出来,我们需要针对这种情况在代码中做好控制

那么下面就让我们尝试用 SAX解析的方式来实现和上一小节中同样的功能吧

MyHandler

public class MyHandler extends DefaultHandler {

    private String nodeName;
    private StringBuilder id;
    private StringBuilder name;
    private StringBuilder version;

    @Override
    public void startDocument() throws SAXException {
        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 {
        super.startElement(uri, localName, qName, attributes);

        //记录当前节点名
        nodeName = localName;
    }

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

        //根据当前的结点名判断将内容添加到哪个StringBulder对象中
        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 {
        super.endElement(uri, localName, qName);

        if("app".equals(localName)){
            Log.d("MyHandler","id is "+id.toString().trim());
            Log.d("MyHandler","name is "+name.toString().trim());
            Log.d("MyHandler","version is "+version.toString().trim());

            //最后把StringBuilder清空
            id.setLength(0);
            name.setLength(0);
            version.setLength(0);
        }
    }

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

我们首先给 id、name和 version结点分别定义了一个 StringBuilder对象,并 在 startDocument()方法里对它们进行了初始化

每当开始解析某个结点的时候,startElement()方法就会得到调用,其中 localName参数记录着当前结点的名字,这里我们把它记录下来

接着在解析结点中具体内容的时候就会调用 characters()方法,我们会根据当前的结点名进行 判断,将解析出的内容添加到哪一个 StringBuilder对象中

最后在 endElement()方法中进行 判断,如果 app结点已经解析完成,就打印出 id、name和 version的内容

需要注意的是, 目前 id、name和 version中都可能是包括回车或换行符的,因此在打印之前我们还需要调用 一下 trim()方法,并且打印完成后还要将 StringBuilder的内容清空掉,不然的话会影响下一 次内容的读取

接下来的工作就非常简单了,修改 MainActivity中的代码,如下所示:

private void sendRequestWithURLConnection() {
        //开启线程发起网络请求
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                try {
                    URL url = new URL("http://192.168.1.51/get_data.xml");
                    connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    InputStream inputStream = connection.getInputStream();
                    //对获取的输入流进行读取
                    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                    StringBuilder response = new StringBuilder();

                    String line;
                    while ((line = reader.readLine()) != null) {
                        response.append(line);
                    }
                    parseXMLWithSAX(response.toString());

                } catch (MalformedURLException e) {

                } catch (ProtocolException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void parseXMLWithSAX(String xmlData){
        SAXParserFactory factory = SAXParserFactory.newInstance();
        XMLReader xmlReader = null;
        try {
            xmlReader = factory.newSAXParser().getXMLReader();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
        MyHandler handler = new MyHandler();
        //将ContentHandler的实例设置到XMLReader中
        xmlReader.setContentHandler(handler);
        //开始执行解析
        try {
            xmlReader.parse(new InputSource(new StringReader(xmlData)));
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        }
    }

在得到了服务器返回的数据后,我们这次去调用 parseXMLWithSAX()方法来解析 XML 数据

parseXMLWithSAX()方法中先是创建了一个 SAXParserFactory的对象,然后再获取到 XMLReader对象,接着将我们编写的 ContentHandler的实例设置到 XMLReader中

最后调 用 parse()方法开始执行解析就好了

现在重新运行一下程序,点击 Send Request按钮后观察 LogCat中的打印日志,你会看 到和Pull方式中解析的一样的结果

相关阅读

在线数据库设计工具-toolfk程序员在线工具网

本文要推荐的[ToolFk]是一款程序员经常使用的线上免费测试工具箱,ToolFk 特色是专注于程序员日常的开发工具,不用安装任何软件,只要

一步步教你分析网站数据(一)

推荐语:强烈推荐下这篇文章。如果网站改版时设计师和甲方的意见相左该怎么办?别吵,让数据说话。今天这篇作者手把手教你如何通过分析

打通账户体系,真的只是用户数据集成那么简单吗?

多个独立的产品在发展到一定阶段后,不管是所有权变更,还是产品间要功能整合,还是用户需要转化促进后来者发展,其实都要面临产品整合的

iOS和Android规范解析:提示框(Toast)对比

在交互设计稿中Toast是其中很常用的一种用户反馈手段,但是作者却发现在iOS中根本没有toast这种部件,那么在设计该如何处理呢?一起来

《谁说菜鸟不会数据分析(入门篇)》总结

一、数据分析方法论营销方面:4P、用户使用行为、STP理论、SWOT管理方面的理论模型:PEST、5W2H、时间管理、生命周期、逻辑树、金字

分享到:

栏目导航

推荐阅读

热门阅读