Android中常见的XML解析方式

基本概念

  1. 概念:extensive markup language(可扩展的标记语言)
    XML是一种通用的数据存储和交换格式,与平台无关,与编程语言无关,与操作系统无关。给数据集成和交互提供了极大的便利。
    将数据格式化成XML文件后,真正实现了数据跨平台的交互和共享。在不同语言中,xml的解析方式都一样。

  2. XML文件格式
    1.每个xml文件中要有一个,且只能有一个xml根节点;
    2.xml文件的数据中不可以 出现”< “或者” >”;

  3. XML的解析方式
    DOM(document object model :文档对象模型):借助文档树模型对xml文档进行分析。
    SAX(simple API for xml :xml的简单api):利用事件流的形式解析XML
    PULL:利用事件流模型来解析XML。
    备注:DOM和SAX解析的优劣分析:DOM是将文档一次性读入到内存,然后以文档树模进行分析节点信息。获取到希望获取的数据;
    而SAX是事件流的形式去分析xml文件。DOM可以做到对文档中部分节点的修改、删除和新增,而SAX无法做到。

PULL解析xml

  1. PULL Parser中的几种event值
    1、START_DOCUMENT: 0
    2、END_DOCUMENT: 1
    3、START_TAG: 2
    4、END_TAG: 3
    5、TEXT: 4

  2. 核心类:
    XmlPullParserFactory
    XmlPullParser

  3. 核心代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // 实例化一个xml pull解析的工厂
    XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
    // 实例化一个xml pull解析对象
    XmlPullParser parser = factory.newPullParser();
    // xml解析对象接收输入流对象
    parser.setInput(instream, "utf-8");
    int event = parser.getEventType();//获取事件类型
    while (event != XmlPullParser.END_DOCUMENT) {
    switch (event) {
    case XmlPullParser.START_DOCUMENT:
    //开始读取文档
    break;
    case XmlPullParser.START_TAG:
    //读取元素开始标签
    break;
    case XmlPullParser.TEXT:
    //读取文本
    break;
    case XmlPullParser.END_TAG:
    //读取闭合标签
    break;
    }
    event = parser.next();//获取下一次解析事件
    }
  4. 常用api

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //获取属性名
    parser.getAttributeName()
    //获取属性值
    parser.getAttributeValue()
    //获取文本值
    parser.getText();
    //获取标签名
    parser.getName();
    //获取下一个文本解析事件,返回文本值(如果当前是START_TAG,且下一个节点是TEXT,则返回文本,如果下一个是END_TAG,返回null,否则则会抛出异常)
    parser.nextText();
    //获取下一个标签解析事件,返回事件类型,如果下一个事件不是START_TAG或END_TAG,则抛出异常
    parser.nextTag();
    //获取下一个解析事件,返回事件类型
    parser.next();

SAX解析xml

SAX解析基本与PULL解析基本相同,也是通过事件流的形式解析xml,SAX的解析借助于DefaultHandler这个处理类。该类实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

class MyXmlHandler extends DefaultHandler {

/**
* 开始读取文档
*
* @throws SAXException
*/

@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);
//uri:命名空间
//localName:不带前缀(命名空间)的标签名
//qName:带前缀的标签名
//attributes:属性集合

}

/**
* 开始读取Text
*/

@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);
//uri:命名空间
//localName:不带前缀(命名空间)的标签名
//qName:带前缀的标签名
}

/**
* 结束读取文档
*/

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

核心代码如下:

1
2
3
4
SAXParserFactory factory=SAXParserFactory.newInstance();
SAXParser parser=factory.newSAXParser();
MyXmlHandler handler=new MyXmlHandler();//继承自DefaultHandler
parser.parse(in,handler);//插入一个自定义的xml处理器

DOM解析xml

  1. DOM树中对节点(NODE)的分类如下
    1、文档节点,Document
    2、元素节点,Element
    3、属性节点,Attribute
    4、文本节点,Text
    5、注释节点,Comment

  2. 核心类:
    DocumentBuilderFactory
    DocumentBuilder
    Doucment,一个xml就是一个Document
    Element ,就是一个元素
    NodeList ,节点集合
    Node,节点,包括文档、元素、属性、文本节点等

  3. 核心代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     DocumentBuilderFactory factory =  DocumentBuilderFactory.newInstance();
    // 使用工厂来实例化一个构造Document的对象
    DocumentBuilder builder = factory.newDocumentBuilder();
    // 利用DocumentBuilder来构造一个Document对象
    Document document = builder.parse(filename);
    // 获取Document文档的根节点对象
    Element root = document.getDocumentElement();
    // 通过根节点,获取到根节点下面的所有二级子节点
    NodeList nodeList = root.getChildNodes();
    // 遍历子节点,获取内部的每一个节点
    for (int i = 0; i < nodeList.getLength(); i++) {
    Node node = nodeList.item(i);
    ...
    }
    ...
  4. 常用api

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    //获取属性值
    element.getAttribute();
    //获取属性节点,没有则null
    element.getAttributeNode();
    //根据标签名返回当前节点下的后代(子子孙孙)节点
    element.getElementsByTagName();
    //获取标签名
    element.getTagName();


    //获取当前节点及其子节点的所有文本内容
    node.getTextContent();
    //获取儿子子节点
    node.getChildNodes();
    //获取节点名字(属性节点返回属性名字,元素节点返回标签名,Text节点返回"#text",Document节点返回"#document")
    node.getNodeName();
    //获取节点值(属性节点返回属性值,文本节点返回文本内容,Comment节点返回内容,CDATASection节点返回内容,其他节点返回null);
    node.getNodeValue();
    //返回当前节点的第一个子节点
    node.getFirstChild();
    //返回当前节点的最后子节点
    node.getLastChild();
    //获取节点类型
    node.getNodeType();
    //返回下一个兄弟节点
    node.getNextSibling();
    //返回上一个兄弟节点
    node.getPreviousSibling();
    //不包含命名空间的名字
    node.getLocalName();
    //以当前节点为根节点获取一个document对象
    node.getOwnerDocument();

解析实战

下面是一段显示近三日天气的xml,分别采用三种方式进行解析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<weatherinfo>
<data d_id="01">
<date>2016-05-07</date>
<icon>d04|n04</icon>
<weather>雷阵雨</weather>
<temperature>36℃~28℃</temperature>
<winddirect>西南风3-4级</winddirect>
</data>
<data d_id="02">
<date>2016-05-08</date>
<icon>d04|n04</icon>
<weather>雷阵雨</weather>
<temperature>32℃~26℃</temperature>
<winddirect>西风3-4级转西北3-4级</winddirect>
</data>
<data d_id="03">
<date>2016-05-09</date>
<icon>d04|n04</icon>
<weather>雷阵雨</weather>
<temperature>32℃~26℃</temperature>
<winddirect>西北风3-4级</winddirect>
</data>
</weatherinfo>

首先根据xml创建一个Weather类。实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class Weather {
private String id;
private String date;
private String icon;
private String weather;
private String temperature;
private String winddirect;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getDate() {
return date;
}

public void setDate(String date) {
this.date = date;
}

public String getIcon() {
return icon;
}

public void setIcon(String icon) {
this.icon = icon;
}

public String getWeather() {
return weather;
}

public void setWeather(String weather) {
this.weather = weather;
}

public String getTemperature() {
return temperature;
}

public void setTemperature(String temperature) {
this.temperature = temperature;
}

public String getWinddirect() {
return winddirect;
}

public void setWinddirect(String winddirect) {
this.winddirect = winddirect;
}
}

  • PULL解析

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    public static List<Weather> pullParser(InputStream in) throws XmlPullParserException, IOException {
    //初始化核心类
    XmlPullParserFactory factory=XmlPullParserFactory.newInstance();
    XmlPullParser parser=factory.newPullParser();
    parser.setInput(in,"utf-8");
    //初始化集合
    List<Weather> list=new ArrayList<>();
    Weather weather=null;
    boolean flag=false;//weather类实例化的标识
    //获取事件类型
    int type=parser.getEventType();
    while(type!=XmlPullParser.END_DOCUMENT){
    switch (type) {
    //开始标签
    case XmlPullParser.START_TAG:
    //如果开始标签是data,初始化Weather类
    if(parser.getName().equals("data")){
    weather=new Weather();
    //读取属性值
    String id=parser.getAttributeValue(null,"d_id");
    weather.setId(id);
    flag=true;
    list.add(weather);

    }
    if(flag){//如果Weather类已实例化,就开始设置值
    if(parser.getName().equals("date")){
    //读取当前START_TAG的下一个文本节点
    weather.setDate(parser.nextText());
    }
    else if(parser.getName().equals("weather")){
    weather.setWeather(parser.nextText());
    }
    else if(parser.getName().equals("icon")){
    weather.setIcon(parser.nextText());
    }
    else if(parser.getName().equals("temperature")){
    weather.setTemperature(parser.nextText());
    }
    else if(parser.getName().equals("winddirect")){
    weather.setWinddirect(parser.nextText());
    }
    }

    break;
    //闭合标签
    case XmlPullParser.END_TAG:
    if(parser.getName().equals("data")){
    flag=false;
    weather=null;
    }
    break;
    }
    //开始下一次解析事件
    type=parser.next();
    }
    return list;
    }
  • SAX解析

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    public static List<Weather> saxParser(InputStream in) throws ParserConfigurationException, SAXException, IOException{
    SAXParserFactory factory=SAXParserFactory.newInstance();
    SAXParser parser=factory.newSAXParser();
    XmlHandler handler=new XmlHandler();//继承自DefaultHandler
    parser.parse(in,handler);//插入一个自定义的xml处理器
    return handler.getList();
    }

    static class XmlHandler extends DefaultHandler{

    private List<Weather> list;
    private String tagName;
    private boolean flag=false;
    private Weather weather;

    /**
    * 开始读取文档
    * @throws SAXException
    */

    @Override
    public void startDocument() throws SAXException {
    super.startDocument();
    list=new ArrayList<>();
    }

    /**
    * 开始读取元素
    */

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
    super.startElement(uri, localName, qName, attributes);
    //uri:命名空间
    //localName:不带前缀(命名空间)的标签名
    //qName:带前缀的标签名
    //attributes:属性集合
    this.tagName=localName;
    if(tagName.equals("data")){
    weather=new Weather();
    String id=attributes.getValue(0);
    weather.setId(id);
    flag=true;
    }
    //
    }

    /**
    * 开始读取Text
    */

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

    String str=new String(ch,start,length).trim();
    if(tagName!=null){
    if(flag){
    if(tagName.equals("date")){
    weather.setDate(str);
    }else if(tagName.equals("icon")){
    weather.setIcon(str);
    }else if(tagName.equals("weather")){
    weather.setWeather(str);
    }else if(tagName.equals("temperature")){
    weather.setTemperature(str);
    }else if(tagName.equals("winddirect")){
    weather.setWinddirect(str);
    }
    }
    }

    }

    /**
    * 结束读取元素
    */

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
    super.endElement(uri, localName, qName);
    if(localName.equals("data")){
    list.add(weather);
    flag=false;
    }
    tagName=null;
    }

    /**
    * 结束读取文档
    */

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


    public List<Weather> getList(){
    return list;
    }


    }
  • DOM解析

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    public static List<Weather> domParser(InputStream in) throws ParserConfigurationException, SAXException, IOException, XmlPullParserException {
    /**
    * 初始化核心API
    */

    DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
    DocumentBuilder builder=factory.newDocumentBuilder();
    Document document=builder.parse(in);
    List<Weather> list=new ArrayList<>();
    NodeList nodes=document.getElementsByTagName("data");

    for(int i=0;i<nodes.getLength();i++ ){
    Element element= (Element) nodes.item(i);
    Weather weather=new Weather();
    weather.setId(element.getAttribute("d_id"));
    NodeList childs=element.getChildNodes();
    for(int j=0;j<childs.getLength();j++){
    Node temp=childs.item(j);
    if(temp.getFirstChild()!=null){
    if(temp.getNodeName().equals("date")){
    weather.setDate(temp.getFirstChild().getNodeValue());
    }else if(temp.getNodeName().equals("icon")){
    weather.setIcon(temp.getFirstChild().getNodeValue());
    }else if(temp.getNodeName().equals("weather")){
    weather.setWeather(temp.getFirstChild().getNodeValue());
    }else if(temp.getNodeName().equals("temperature")){
    weather.setTemperature(temp.getFirstChild().getNodeValue());
    }else if(temp.getNodeName().equals("winddirect")){
    weather.setWinddirect(temp.getFirstChild().getNodeValue());
    }

    }}
    list.add(weather);

    }
    return list;
    }

END