XML解析方式

<html>
    <head>
        <title> New Document </title>
    </head>
    <body>
        <apps>
            <app group="1" category="Map">
                <id>13</id>
                <name lang="en">Google Maps</name>
                <version>1.0</version>
            </app>
            <app group="2" category="Browser">
                <id>14</id>
                <name lang="en">Chrome</name>
                <version>2.0</version>
            </app>
            <app group="3" category="Store">
                <id>17</id>
                <name lang="en">Google Play</name>
                <version>2.3</version>
            </app>
        </apps>
    </body>
</html>

Pull解析方式

PULL解析器的运行方式和SAX类似,都是基于事件的模式。不同的是,在PULL解析过程中,我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器。
PULL是顺序扫描XML的每一行,并且根据扫描到的事件来做出不同的行为

PULL一共有5种事件类型:
* START_DOCUMENT = 0:文档的开始,解析器尚未读取任何输入。
* END_DOCUMENT = 1:文档的结束。
* START_TAG = 2:开始标签的解析。
* END_TAG = 3:结束标签的解析。
* TEXT:标签内元素的内容解析。

public class MainActivity extends AppCompatActivity {

    private Button pullXml;
    private TextView responseText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        pullXml = (Button) findViewById(R.id.pull_xml);
        responseText = (TextView) findViewById(R.id.response);
        pullXml.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try{
                            OkHttpClient client = new OkHttpClient();
                            //复制IPv4地址
                            Request request = new Request.Builder()
                                    .url("http://xxx.xxx.x.xxx:8080/server/data.xml")
                                    .build();
                            Response response = client.newCall(request).execute();
                            String responseData = response.body().string();
                            parseXMLWithPull(responseData);
                        } catch (IOException e){
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        });
    }

    private void parseXMLWithPull(String xmlData){
        StringBuilder dataBuider = new StringBuilder();
        try{
            //解析工厂
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            //解析器
            XmlPullParser xmlPullParser = factory.newPullParser();
            xmlPullParser.setInput(new StringReader(xmlData));

            //得到一个解析事件
            int eventType = xmlPullParser.getEventType();//0
            //如果当前解析事件不等于XmlPullParser.END_DOCUMENT 说明解析工作没有完成
            while(eventType != XmlPullParser.END_DOCUMENT){//1
                String nodeName = xmlPullParser.getName();
                switch (eventType){
                    //开始解析某个节点
                    case XmlPullParser.START_TAG://2

                        if("title".equals(nodeName)){
                            dataBuider.append("title: " + xmlPullParser.nextText() + "\n");
                        } else if("app".equals(nodeName)){
                            dataBuider.append("app group: " + xmlPullParser.getAttributeValue(null,"group") +
                                           " category: " + xmlPullParser.getAttributeValue(null,"category") + "\n");
                        } else if("id".equals(nodeName)){
                            dataBuider.append("id: " + xmlPullParser.nextText() + "\n");
                        } else if("name".equals(nodeName)){
                            dataBuider.append( "lang: " + xmlPullParser.getAttributeValue(null,"lang") +
                                            " name: " + xmlPullParser.nextText() + "\n" );
                        } else if("version".equals(nodeName)){
                            dataBuider.append("version: " + xmlPullParser.nextText() + "\n");
                        }
                        break;
                    //完成解析某个节点
                    case XmlPullParser.END_TAG://3
                       if("app".equals(nodeName)){
                           dataBuider.append("\n");
                       }
                }
                //调用next()方法可以获取下一个解析事件
                eventType = xmlPullParser.next();
            }
            showResponse(dataBuider.toString());

            //START_DOCUMENT = 0
            //END_DOCUMENT = 1
            //START_TAG = 2
            //END_TAG = 3

        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public  void showResponse(final String response){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                responseText.setText(response);
            }
        });
    }
}

这里写图片描述


SAX解析方式

一、概述

 SAX,全称Simple API for XML,是一种以事件驱动的XMl API,是XML解析的一种新的替代方法,解析XML常用的还有DOM解析,PULL解析(Android特有),SAX与DOM不同的是它边扫描边解析,自顶向下依次解析,由于边扫描边解析,所以它解析XML具有速度快,占用内存少的优点,对于Android等CPU资源宝贵的移动平台来说是一个巨大的优势。

SAX的优点:
1.解析速度快
2.占用内存少

SAX的缺点:
1.无法知道当前解析标签(节点)的上层标签,及其嵌套结构,仅仅知道当前解析的标 签的名字和属性,要知道其他信息需要程序猿自己编码
2.只能读取XML,无法修改XML
3.无法随机访问某个标签(节点)

SAX解析适用场合:
1.对于CPU资源宝贵的设备,如Android等移动设备
2.对于只需从xml读取信息而无需修改xml

二、SAX解析的步骤

解析步骤很简单,可分为以下四个步骤

1.得到xml文件对应的资源,可以是xml的输入流,文件和uri
2.得到SAX解析工厂(SAXParserFactory)
3.由解析工厂生产一个SAX解析器(SAXParser)
4.传入输入流和handler给解析器,调用parse()解析

ContentHandler.class

public class ContentHandler extends DefaultHandler {

    private StringBuilder dataBuider;
    private String currentTag;//记录当前解析到的节点名称

    //文档解析开始时调用,该方法只会调用一次
    @Override
    public void startDocument() throws SAXException {
        dataBuider= new StringBuilder();
    }

    /**
     * 节点解析开始调用
     * @param uri : 命名空间的uri
     * @param localName : 标签的名称
     * @param qName : 带命名空间的标签名称
     */
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if("app".equals(localName)) {
           for(int i = 0; i < attributes.getLength(); i++){
               if("group".equals(attributes.getLocalName(i))){
                   dataBuider.append("app group: " + attributes.getValue(i));
                }else if("category".equals(attributes.getLocalName(i))){
                   dataBuider.append(" category: " + attributes.getValue(i) + "\n");
               }
           }
        }

        if("name".equals(localName)){
            for(int j = 0; j < attributes.getLength(); j++){
                if("lang".equals(attributes.getLocalName(j))){
                    dataBuider.append("lang: " + attributes.getValue(j) + " ");
                }
            }
        }
        //记录当前节点名
        currentTag = localName;
    }

    /**
     * 解析标签的内容的时候调用
     * @param ch : 当前读取到的TextNode(文本节点)的字节数组
     * @param start : 字节开始的位置,为0则读取全部
     * @param length : 当前TextNode的长度
     * @throws SAXException
     */
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        //根据当前的节点名判断内容添加到哪一个StringBuider对象中
        String value = new String(ch, start, length);
        if ("id".equals(currentTag)){
            dataBuider.append("id: " + value + "\n");
        } else if ("name".equals(currentTag)){
            dataBuider.append("name: " + value + "\n");
        } else if ("version".equals(currentTag)){
            dataBuider.append("version: " + value + "\n");
        }
    }

    //标签(节点)解析结束后调用
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {

        currentTag = null;
    }

    //文档解析结束后调用,该方法只会调用一次
    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }

    public StringBuilder getXmlData() {
        return dataBuider;
    }
}

MainActivity.class

public class MainActivity extends AppCompatActivity {

    private Button saxXml;
    private TextView responseText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        saxXml = (Button) findViewById(R.id.sax_xml);
        responseText = (TextView) findViewById(R.id.response);
        saxXml.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try{
                            OkHttpClient client = new OkHttpClient();
                            Request request = new Request.Builder()
                                    .url("http://xxx.xxx.x.xxx:8080/server/data.xml")
                                    .build();
                            Response response = client.newCall(request).execute();
                            String responseData = response.body().string();
                            parseXMLWithSax(responseData);
                        } catch (IOException e){
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        });
    }

    private void parseXMLWithSax(String xmlData){
        try{
            //得到SAX解析工厂
            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)));

            StringBuilder dataBuider= handler.getXmlData();
            showResponse(dataBuider.toString());
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    public  void showResponse(final String response){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                responseText.setText(response);
            }
        });
    }
}

这里写图片描述

1、xml解析开始,startDocument被调用,这个方法在整个xml解析过程中调用了一次,所以我们可以在这个方法里面初为解析XML做一些准备,比如初始化变量
2、解析每遇到一个标签都会经历startElement-characters-endElement这个过程,即每一个标签都会触发startElement-characters-endElement
3、通过users这个根节点的解析,user标签解析以及name,password标签解析过程,我们知道user标签是users的子标签,name和password标签是user标签的子标签,我们知道当解析一个标签的时候,如果该标签有子标签,则先回调用该标签的startElement方法,这里面可以先得到该标签的属性信息,然后触发characters解析该标签的内容(值),然后子标签触发startElement-characters-endElement(子标签触发),最后该标签触发endElement,该标签解析结束

这里写图片描述


Dom解析方式

https://yq.aliyun.com/articles/3367

public class MainActivity extends AppCompatActivity {

    private Button domXml;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        domXml = (Button) findViewById(R.id.dom_xml);
        domXml.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try{
                            OkHttpClient client = new OkHttpClient();
                            Request request = new Request.Builder()
                                    .url("http://xxx.xxx.x.xxx:8080/server/data.xml")
                                    .build();
                            Response response = client.newCall(request).execute();
                            String responseData = response.body().string();
                            InputStream in = new ByteArrayInputStream(responseData.getBytes());
                            parseXMLWithDOM(in);
                        } catch (IOException e){
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        });
    }

    private void parseXMLWithDOM(InputStream xmlData){

        try{
            //通过抽象工厂类DocumentBuilderFactory的静态方法newInstance获得一个工厂实例对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            //通过工厂实例对象获得一个DocumentBuilder对象
            DocumentBuilder db = factory.newDocumentBuilder();
            //通过DocumentBuilder对象的parse方法加载inputStream文件进行解析转换为Document对象
            Document document = db.parse(xmlData);
            //通过Document对象的getElementsByTagName()方法获得元素节点集合
            NodeList appList = document.getElementsByTagName("app");

            //遍历每一个元素节点
            int size = appList.getLength();
            Log.e("log","一共有" + size + "个节点");

            //遍历每个app元素节点
            for(int i = 0; i < size;i++){
                //通过item方法获取每一个app元素节点
                Node appNode = appList.item(i);
                //获取app元素节点所有属性节点集合
                NamedNodeMap attriMap = appNode.getAttributes();
                Log.e("log","第" + (i+1) + "个节点");
                int attriSize = attriMap.getLength();
                Log.e("log","第" + (i+1) + "个节点一共有" + attriSize + "个属性节点");

                //属性
                for(int j = 0; j < attriSize ;j++){
                    //通过item方法获取app元素节点的属性节点
                    Node attriNode = attriMap.item(j);

                    Log.e("log",
                            "属性节点:(" +
                            " type: " + attriNode.getNodeType() + // 获取属性节点属性类型
                            " ,name: " + attriNode.getNodeName() + // 获取属性节点属性名称
                            " ,value: " + attriNode.getNodeValue() +")"); // 获取属性节点属性值

                }

                //获取app元素节点的子节点集合
                NodeList chidNodeList = appNode.getChildNodes();
                int childSize = chidNodeList.getLength();
                Log.e("log","一共有" + childSize + "个子节点(元素节点和文本节点)");
                for(int k =0; k < childSize;k++){
                    //获取子节点
                    Node childNode = chidNodeList.item(k);
                    //区分Elemet类型节点和Text类型节点
                    if(childNode.getNodeType() == Node.ELEMENT_NODE){//1
                        //获取子节点所有属性节点集合
                        NamedNodeMap childAttriMap = childNode.getAttributes();
                        String type = "";
                        String name = "";
                        String value = "";
                        //属性
                        for(int m = 0 ; m < childAttriMap.getLength(); m++){
                            //通过item方法获取子节点的属性节点
                            Node childAttriNode = childAttriMap.item(m);
                            type = childAttriNode.getNodeType()+"";
                            name = childAttriNode.getNodeName()+"";
                            value = childAttriNode.getNodeValue()+"";

                        }
                        Log.e("log",
                                "元素节点:(" +
                                " type:" + childNode.getNodeType() +             //获取元素子节点类型
                                " ,name:" + childNode.getNodeName() +           //获取元素子节点名称
                                " ,value:" + childNode.getNodeValue() + " )" + //获取元素子节点值
                                "属性节点:(" +
                                " type:" + type +
                                " ,name:" + name +
                                " ,value:"+value + " )" +
                                "文本节点:(" +
                                " type:" + childNode.getFirstChild().getNodeType() +
                                " name: " + childNode.getFirstChild().getNodeName() +
                                " value:" + childNode.getFirstChild().getNodeValue() + " )");
                    }
                }

            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }

}

这里写图片描述


递归解析XML

public class MainActivity extends AppCompatActivity {

    StringBuilder dataBuider = new StringBuilder();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        try{
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = factory.newDocumentBuilder();
            Document document = db.parse(getAssets().open("data.xml"));
            //获得根节点
            Element root = document.getDocumentElement();
            //获取根节点的子节点
            NodeList nodeList = root.getChildNodes();
            paseXMLWithDOM(nodeList);
            Log.e("log", dataBuider.toString());
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    //解析子节点
    private void paseXMLWithDOM(NodeList nodeList){
        for(int i = 0; i < nodeList.getLength();i++){
            Node node = nodeList.item(i);
            //区分Elemet类型节点和Text类型节点
            if(node.getNodeType() == Node.ELEMENT_NODE){
                //获取元素节点名和值
                String nodeName = node.getNodeName();
                String nodeValue = node.getFirstChild().getNodeValue();

                //获取元素节点的属性节点
                NamedNodeMap attrMap = node.getAttributes();
                if(attrMap.getLength()>0){
                    //元素节点包含属性节点
                    StringBuilder attrBuilder = new StringBuilder();
                    for(int j = 0; j < attrMap.getLength();j++){
                        Node attrNode = attrMap.item(j);
                        attrBuilder.append(attrNode.getNodeName()+":\""+attrNode.getNodeValue()+"\" ");
                    }
                    dataBuider.append(new String("<"+nodeName +" "+ attrBuilder.toString()+">"+nodeValue).trim());
                } else {
                    //元素节点没有包含属性节点
                    dataBuider.append(new String("<"+nodeName+ ">"+nodeValue).trim());
                }

                //如果dataBuider是 > 结尾就换行
                if(dataBuider.lastIndexOf(">") == dataBuider.length()-1){
                    dataBuider.append("\n");
                }
                //元素节点是否有子节点
                if(node.hasChildNodes()) {
                    //递归解析元素节点的子节点
                    paseXMLWithDOM(node.getChildNodes());
                }
                dataBuider.append("</"+nodeName+">"+"\n");
            }
        }
    }

}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值