一. 前言

1. 了解 XmlResourceParser

1
XmlResourceParser extends XmlPullParser

在Android中一般使用 XmlResourceParser,解析的Xml文件需要放在 Res文件夹下面的 xml文件夹 中。

2. 常用的方法

1
2
3
4
5
6
7
/**
* Returns the type of the current event (START_TAG, END_TAG, TEXT, etc.)
*
* @see #next()
* @see #nextToken()
*/
int getEventType() throws XmlPullParserException;
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
/**
* This array can be used to convert the event type integer constants
* such as START_TAG or TEXT to
* to a string. For example, the value of TYPES[START_TAG] is
* the string "START_TAG".
*
* This array is intended for diagnostic output only. Relying
* on the contents of the array may be dangerous since malicious
* applications may alter the array, although it is final, due
* to limitations of the Java language.
*/
String [] TYPES = {
"START_DOCUMENT",
"END_DOCUMENT",
"START_TAG",
"END_TAG",
"TEXT",
"CDSECT",
"ENTITY_REF",
"IGNORABLE_WHITESPACE",
"PROCESSING_INSTRUCTION",
"COMMENT",
"DOCDECL"
};

int START_DOCUMENT = 0;
int END_DOCUMENT = 1;
int START_TAG = 2;
int END_TAG = 3;
int TEXT = 4;
int CDSECT = 5;
int ENTITY_REF = 6;
int IGNORABLE_WHITESPACE = 7;
int PROCESSING_INSTRUCTION = 8;
int COMMENT = 9;
int DOCDECL = 10;
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* For START_TAG or END_TAG events, the (local) name of the current
* element is returned when namespaces are enabled. When namespace
* processing is disabled, the raw name is returned.
* For ENTITY_REF events, the entity name is returned.
* If the current event is not START_TAG, END_TAG, or ENTITY_REF,
* null is returned.
* <p><b>Please note:</b> To reconstruct the raw element name
* when namespaces are enabled and the prefix is not null,
* you will need to add the prefix and a colon to localName..
*
*/
String getName();
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
/**
* Returns the given attributes value.
* Throws an IndexOutOfBoundsException if the index is out of range
* or current event type is not START_TAG.
*
* <p><strong>NOTE:</strong> attribute value must be normalized
* (including entity replacement text if PROCESS_DOCDECL is false) as described in
* <a href="http://www.w3.org/TR/REC-xml#AVNormalize">XML 1.0 section
* 3.3.3 Attribute-Value Normalization</a>
*
* @see #defineEntityReplacementText
*
* @param index zero-based index of attribute
* @return value of attribute (null is never returned)
*/
String getAttributeValue(int index);


/**
* Returns the attributes value identified by namespace URI and namespace localName.
* If namespaces are disabled namespace must be null.
* If current event type is not START_TAG then IndexOutOfBoundsException will be thrown.
*
* <p><strong>NOTE:</strong> attribute value must be normalized
* (including entity replacement text if PROCESS_DOCDECL is false) as described in
* <a href="http://www.w3.org/TR/REC-xml#AVNormalize">XML 1.0 section
* 3.3.3 Attribute-Value Normalization</a>
*
* @see #defineEntityReplacementText
*
* @param namespace Namespace of the attribute if namespaces are enabled otherwise must be null
* @param name If namespaces enabled local name of attribute otherwise just attribute name
* @return value of attribute or null if attribute with given name does not exist
*/
String getAttributeValue(String namespace, String name);
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
/**
* If current event is START_TAG then if next element is TEXT then element content is returned
* or if next event is END_TAG then empty string is returned, otherwise exception is thrown.
* After calling this function successfully parser will be positioned on END_TAG.
*
* <p>The motivation for this function is to allow to parse consistently both
* empty elements and elements that has non empty content, for example for input: <ol>
* <li>&lt;tag&gt;foo&lt;/tag&gt;
* <li>&lt;tag&gt;&lt;/tag&gt; (which is equivalent to &lt;tag/&gt;
* both input can be parsed with the same code:
* <pre>
* p.nextTag()
* p.requireEvent(p.START_TAG, "", "tag");
* String content = p.nextText();
* p.requireEvent(p.END_TAG, "", "tag");
* </pre>
* This function together with nextTag make it very easy to parse XML that has
* no mixed content.
*
*
* <p>Essentially it does this
* <pre>
* if(getEventType() != START_TAG) {
* throw new XmlPullParserException(
* "parser must be on START_TAG to read next text", this, null);
* }
* int eventType = next();
* if(eventType == TEXT) {
* String result = getText();
* eventType = next();
* if(eventType != END_TAG) {
* throw new XmlPullParserException(
* "event TEXT it must be immediately followed by END_TAG", this, null);
* }
* return result;
* } else if(eventType == END_TAG) {
* return "";
* } else {
* throw new XmlPullParserException(
* "parser must be on START_TAG or TEXT to read text", this, null);
* }
* </pre>
*
* <p><strong>Warning:</strong> Prior to API level 14, the pull parser returned by {@code
* android.util.Xml} did not always advance to the END_TAG event when this method was called.
* Work around by using manually advancing after calls to nextText(): <pre>
* String text = xpp.nextText();
* if (xpp.getEventType() != XmlPullParser.END_TAG) {
* xpp.next();
* }
* </pre>
*/
String nextText() throws XmlPullParserException, IOException;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Get next parsing event - element content will be coalesced and only one
* TEXT event must be returned for whole element content
* (comments and processing instructions will be ignored and entity references
* must be expanded or exception must be thrown if entity reference can not be expanded).
* If element content is empty (content is "") then no TEXT event will be reported.
*
* <p><b>NOTE:</b> empty element (such as &lt;tag/>) will be reported
* with two separate events: START_TAG, END_TAG - it must be so to preserve
* parsing equivalency of empty element to &lt;tag>&lt;/tag>.
* (see isEmptyElementTag ())
*
* @see #isEmptyElementTag
* @see #START_TAG
* @see #TEXT
* @see #END_TAG
* @see #END_DOCUMENT
*/

int next() throws XmlPullParserException, IOException;

二. 实际小例子

1. 待解析的Xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<web>
<item id="0" url="https://www.baidu.com">百度</item>
<item id="1" url="https://www.taobao.com">淘宝</item>
<item id="2" url="https://www.qq.com">腾讯</item>
<item id="3" url="https://www.aili.com">阿里巴巴</item>
<item id="4" url="https://www.taobao.com">淘宝</item>
<item id="5" url="https://www.wechat.com">微信</item>
<item id="6" url="https://www.timi.com">天美</item>
<item id="7" url="https://www.guangzi.com">光子</item>
<item id="8" url="https://www.taoken.com">字节跳动</item>
<item id="9" url="https://www.douyin.com">抖音</item>
</web>

2. Activity中的调用

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
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//PULL解析
testPULLParse();
}

/**
* PULL解析 使用XmlResourceParser 只有xml里面才可以读到
*/
private void testPULLParse(){
//存储解析的模型资源
List<WebItem> webItems = null;

//临时的模型类
WebItem webItem = null;

//获取Xml资源解析器
XmlResourceParser xmlResourceParser = getResources().getXml(R.xml.test);

//解析
try {

//事件类型
int eventType = xmlResourceParser.getEventType();

//只要还没有到文档结束的地方就继续解析
while (xmlResourceParser.getEventType() != XmlResourceParser.END_DOCUMENT) {

if (eventType == XmlResourceParser.START_DOCUMENT){

//如果当前的位置是文档的开始位置,实例化模型集合
webItems = new ArrayList<>();

}else if (eventType == XmlResourceParser.START_TAG){

//如果当前位置是标签开始的位置

//如果当前标签是item,实例化WebItem,根据索引获得属性值
if (TextUtils.equals(xmlResourceParser.getName(),"item")){
webItem = new WebItem();

webItem.setId(Integer.parseInt(xmlResourceParser.getAttributeValue(0)));
webItem.setUrl(xmlResourceParser.getAttributeValue(1));
webItem.setContent(xmlResourceParser.nextText());

assert webItems != null;
webItems.add(webItem);
}
}

//继续解析
eventType = xmlResourceParser.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();

Toast.makeText(this, "没有XMlPull解析器", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();

Toast.makeText(this, "IO异常", Toast.LENGTH_SHORT).show();
}

//关闭
xmlResourceParser.close();

for (WebItem item : webItems) {
//Toast.makeText(this, "id:"+item.getId()+" url:"+item.getUrl()+" content:"+item.getContent(), Toast.LENGTH_SHORT).show();
//显示数据
addToRootLayout((LinearLayout) findViewById(R.id.root),item);
}
}

/**
* 将WebItem显示到布局中
* @param layout
* @param webItem
*/
private void addToRootLayout(LinearLayout layout, WebItem webItem){
View inflate = LayoutInflater.from(this).inflate(R.layout.web_item_layout, null);
TextView id_text = inflate.findViewById(R.id.id);
TextView content_text = inflate.findViewById(R.id.content);
TextView url_text = inflate.findViewById(R.id.url);

id_text.setText(String.valueOf(webItem.getId()));
content_text.setText(webItem.getContent());
url_text.setText(webItem.getUrl());

layout.addView(inflate);
}
}

3. 运行结果

4. 源码地址

ParseXml

参考文章

Pull方式解析XML文件