android | xml文件解析

每种语言都有解析xml文档的插件包,在java中常见的有两种,Dom和SAX两种方式。

介绍

SAX(Simple API for XML)是一个解析速度快并且占用内存少的XML解析器,非常适合用于Android等移动设备。
SAX解析XML文件采用的是事件驱动,也就是说,它并不需要解析完整个文档,在按内容顺序解析文档的过程中,SAX会判断当前读到的字符是否合法XML语法中的某部分,如果符合就会触发事件。
所谓事件,其实就是一些回调(callback)方法,这些方法(事件)定义在ContentHandler接口。

ContentHandler

既然回调的触发事件定义在ContentHandler中,那么不妨看看这个类
org.xml.sax.ContentHandler

大多数SAX应用程序都实现了这个接口,这个解析器就关联了一些文档事件,如元素开始、元素结束和文本数据。
在这个接口中事件的顺序是非常重要,所有的元素内容都出现在startElement事件和endElement事件之间。

abstract voidcharacters(char[] ch, int start, int length) 接收字符数据的通知。
abstract voidendDocument() 接收文档结束的通知。
abstract voidendElement(String uri, String localName, String qName) 接收元素结束的通知。
abstract voidendPrefixMapping(String prefix) 结束前缀URI映射的范围。
abstract voidignorableWhitespace(char[] ch, int start, int length) 接收元素内容中可忽略空白的通知。
abstract voidprocessingInstruction(String target, String data) 接收处理指令的通知。
abstract voidsetDocumentLocator(Locator locator) 接收用于查找SAX文档事件原点的对象。
abstract voidskippedEntity(String name) 接收跳过的实体的通知。
abstract voidstartDocument() 接收文档开头的通知。
abstract voidstartElement(String uri, String localName, String qName, Attributes atts) 接收元素开头的通知。
abstract voidstartPrefixMapping(String prefix, String uri) 开始前缀-URI名称空间映射的范围。

看上面的函数,都是抽象函数,如果我们实现ContentHandler,就会比较麻烦,故而我们找它已知的子类DefaultHandler(SAX2事件处理程序的默认基类。)

案例

这里解析的xml文件是在res/raw/person.xmlraw是新建的文件夹。具体的xml如下:

<?xml version="1.0" encoding="utf-8"?>
<persions>
    <person>
        <name>Tom</name>
        <age>20</age>
        <sex></sex>
    </person>
</persions>

然后,就是写一个解析类,saxParser.java,它继承DefaultHandler,简单的实现如下:

package com.weizu.intent;
import java.util.ArrayList;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import android.util.Log;

public class saxParser extends DefaultHandler {
    private String tagName = null;
    private person pn = null;
    private ArrayList<person> list = new ArrayList<person>();

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        super.characters(ch, start, length);
        //处理文本标签,容易猜想。ch字符数组,start开始位置,长度
        if(tagName != null){
            String data = new String(ch, start, length);
            if(tagName.equals("name")){
                Log.i("name", data);
                pn.setName(data);
            }else if(tagName.equals("age")){
                Log.i("age", data);
                pn.setAge(Integer.parseInt(data));
            }else if(tagName.equals("sex")){
                Log.i("sex", data);
                pn.setSex(data);
            }
        }
    }

    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);
        //由于开始,结束,文本都是调用这三个函数,故而需要标记
        tagName = localName;
        if(localName.equals("person")){
            pn = new person();
        }
    }
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        super.endElement(uri, localName, qName);
        if(localName.equals("person")){
            list.add(pn);
            pn = null;
        }
        tagName = null;
    }
    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
    }
    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }

    //返回数据
    public ArrayList<person> getPersons(){
        return list;
    }
}

最后就是调用了,布局文件是一个按钮,这里就不给出了,MainActivity.java如下:

public class MainActivity extends Activity{
    private Button btn;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btn = (Button)findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                InputStream in = getResources().openRawResource(R.raw.person);
                if(in!=null){
                    ArrayList<person> list = saxParser(in);
                    if(list!=null){
                        Toast.makeText(MainActivity.this, list.get(0).toString(), 20).show();
                    }else{
                        Toast.makeText(MainActivity.this, "resulut is null", 20).show();
                    }
                }else{
                    Toast.makeText(MainActivity.this, "input is null", 20).show();
                }
            }
        });

    }

    public ArrayList<person> saxParser(InputStream inputstream){
        try {
            SAXParserFactory spf = SAXParserFactory.newInstance();
            SAXParser saxParser = spf.newSAXParser();
            saxParser sax = new saxParser();
            saxParser.parse(inputstream, sax);
            inputstream.close();
            return sax.getPersons();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

效果:


   Reprint policy


《android | xml文件解析》 by 无涯明月 is licensed under a Creative Commons Attribution 4.0 International License
 Previous
深思与反省 深思与反省
哎,看上篇反省就是上个月的明天,突然自己又很想写一篇来记录此时的感受。 买菜的时候,翻了翻好几个月都不曾碰的微信朋友圈,然后就刷了一个月的动态。感觉很方,落寞感一下子就涌上了心头,看着别个的梦想和生活,谈不上羡慕和佩服,但是想想自己现在
2019-08-28
Next 
AndroidAPI阅读不会单词 AndroidAPI阅读不会单词
今天是2019年8月22日,过得太快了。还是争取好好学几天。虽然在学Android的时候,经常做的就是百度看看,看别人的案例,但好像大佬都会自己看API。终究是没有养成看API的习惯,所以要开始培养。 官方文档:地址 encapsula
2019-08-22
  TOC