Android SAX API: XmlResourceParser及其扩展应用

分类: Android 2011-05-23 15:16 253人阅读 评论(0) 收藏 举报

XmlResourceParser继承了2个接口:AttributeSetXmlPullParser。其中XmlPullParser定义了Android SAX框架。跟Java SAX API相比,XmlPullParser令人难以置信地简单。

一、使用XmlResourceParser读取资源束中的xml

资源束是应用程序编译后的应用程序包的别称。如果我们有一个xml文件是放在应用程序包内并随编译后的包一起发布的,那么使用XmlResourceParser读取xml非常简单。

首先在res目录下新建目录xml。在xml目录中新建xml文件,例如tqqk.xml

<? xml version = "1.0" encoding = "utf-8" ?>

< tqqk >

< item name = " " id = "78" />

< item name = " 多云 " id = "80" />

< item name = " " id = "79" />

< item name = " 小(阵)雨 " id = "4" />

< item name = " 中雨 " id = "5" />

< item name = " 大雨 " id = "802" />

< item name = " 大到暴雨 " id = "7" />

< item name = " 雷阵雨 " id = "181" />

< item name = " 雨夹雪 " id = "84" />

< item name = " 小雪 " id = "10" />

< item name = " 中雪 " id = "11" />

< item name = " 大到暴雪 " id = "83" />

< item name = " 冰雹 " id = "13" />

< item name = " " id = "14" />

< item name = " 多云转晴 " id = "85" />

< item name = " 阴湿 " id = "182" />

< item name = " 闷热 " id = "202" />

</ tqqk >

这是一个天气情况列表,每个item元素有两个属性:nameid。也就是说我们给每种天气定义一个名字和id

由于我们的这个xml文档中并没有定义DTD或者SchemaEclipse会提示一个警告,不用理会它。

现在我们需要用 XmlResourceParser 来读取xml文件并转换为KVPkey value pairs)对象。

新建一个类 KVPsFromXml

public class KVPsFromXml {

private Context ctx ;

public KVPsFromXml(Context c) {

ctx = c;

}

public Map<String, String> TqqkFromXml(String filename) {

Map<String, String> map = new HashMap<String, String>();

// 获得处理 android xml 文件的 XmlResourceParser 对象

XmlResourceParser xml = ctx .getResources().getXml(

getResIDFromXmlFile(filename));

try {

// 切换到下一个状态,并获得当前状态的类型

int eventType = xml.next();

while ( true ) {

// 文档开始状态

if (eventType == XmlPullParser. START_DOCUMENT ) {

}

// 标签开始状态

else if (eventType == XmlPullParser. START_TAG ) {

// 将标签名称和当前标签的深度(根节点的 depth 1 ,第 2 层节点的 depth 2 ,类推)

switch (xml.getDepth()){

case 1:

break ;

case 2:

// item name id 属性,并放入 map

String key=xml.getAttributeValue( null , "name" );

String value=xml.getAttributeValue( null , "id" );

map.put(key, value);

break ;

}

// 获得当前标签的属性个数

// int count = xml.getAttributeCount();

// 将所有属性的名称和属性值添加到 StringBuffer 对象中

// for (int i = 0; i < count; i++) {

// sb.append(xml.getAttributeName(i)

// + "xml.getAttributeValue(i)");

// }

}

// 标签结束状态

else if (eventType == XmlPullParser. END_TAG ) {

}

// 读取标签内容状态

else if (eventType == XmlPullParser. TEXT ) {

}

// 文档结束状态

else if (eventType == XmlPullParser. END_DOCUMENT ) {

// 文档分析结束后,退出 while 循环

break ;

}

// 切换到下一个状态,并获得当前状态的类型

eventType = xml.next();

}

} catch (Exception e) {

e.printStackTrace();

}

return map;

}

public int getResIDFromXmlFile(String file) {

int ret = 0;

@SuppressWarnings ( "rawtypes" )

Class c = null ;

try {

c = Class.forName ( "ydtf.ydqx.R$xml" );

Field field = c.getDeclaredField(file);

if (field != null )

ret = field.getInt(c);

} catch (Exception ex) {

ex.printStackTrace();

}

return ret;

}

}

该类的构造函数需要传递一个Context参数,即把使用这个类的Activity引用传递给它。因为Activity有一个很便利的方法getResource可以访问并加载 R 对象中的类(资源)。由于 XmlPullParser接口定义了Android SAXXMLPULL V1 API ( 请参考http://www.xmlpull.org ) ,我们可以使用SAX解析中的4个事件:

START_TAG,TEXT,END_TAG,END_DOCUMENT(这跟Java SAX中的4个事件是对应的)。因此在接下来的while循环中,我们针对4个事件进行了分别的处理,从而读取xml中的各个元素及其属性,并组装成KVP(键值对)放入Map中。

ctx .getResources().getXml().getResIDFromXmlFile()) 方法可以获得一个 XmlResourceParser 对象。但是 getResIDFromXmlFile 方法要求提供一个int型的资源id(即R.java中定义的各种16进制数)为参数。

由于res文件夹中的各种资源被映射入R.java的类及字段——具体说,res目录下的子目录映射为R.java中的内部类,子目录中的文件被映射为内部类的字段。因此,xml目录下的tqqk.xml会被映射为R.java中的xml类的tqqk字段。用java表述则是“包名.R.$xml.tqqk”。通过java.reflect包,我们可以得到这个xml文件的资源id

接下来,我们在Activity中取得xml解析的结果--Map对象:

public void onCreate(Bundle savedInstanceState) {

super .onCreate(savedInstanceState);

setContentView(R.layout. ydqxlogin );

// read the xml file:tqqk.xml

KVPsFromXml xml= new KVPsFromXml( this );

tqqk_map =xml.TqqkFromXml( "tqqk" );

Log.i ( "tqqk_map" , tqqk_map + "" );

}

我们可以在LogCat中看到打印出来的结果:

{é — ·ç ƒ ­=202, å¤§å ˆ °æ š ´é › ¨=7, é ˜ ´æ¹¿=182, å¤§å ˆ °æ š ´é › ª=83, å † °é › ¹=13, ä¸­é › ¨=5, é › ·é ˜ µé › ¨=181, ä¸­é › ª=11, é › ¨å¤¹é › ª=84, å¤§é › ¨=802, é ˜ ´=79, é › ¾=14, å¤ š äº ‘ =80, å°  é › ª=10, æ ™ ´=78, å°  ï¼ ˆ é ˜ µï¼ ‰ é › ¨=4, å¤ š äº ‘ è½¬æ ™ ´=85}

由于name使用了中文,所以出现了乱码。如果我们用adb logcat命令的话,则可以显示中文:

{大雨=802, 冰雹=13, 雷阵雨=181, 阴湿=182, =78, =79, 闷热=202, 多云=80, 雨夹雪=84, 小(阵)雨=4, 中雨=5, 小雪=10, 大到暴雨=7, 中雪=11, =14, 多云转晴=85, 大到暴雪=83}

二、直接从资源束之外读取xml

有时候,xml并不总是随资源束一起编译,比如说从网络流中获取的xml

那么我们可以直接使用XmlPullParser接口。

修改KVPsFromXml类的 TqqkFromXml 方法代码:

public Map<String, String> TqqkFromXml(InputStream in,String encode){

Map<String, String> map = new HashMap<String, String>();

try {

XmlPullParserFactory factory = XmlPullParserFactory.newInstance ();

factory.setNamespaceAware( true );

XmlPullParser xpp = factory.newPullParser();

xpp.setInput(in,encode);

// 切换到下一个状态,并获得当前状态的类型

int eventType = xpp.getEventType();

while ( true ) {

// 文档开始状态

if (eventType == XmlPullParser. START_DOCUMENT ) {

}

// 标签开始状态

else if (eventType == XmlPullParser. START_TAG ) {

// 将标签名称和当前标签的深度(根节点的 depth 1 ,第 2 层节点的 depth 2 ,类推)

switch (xpp.getDepth()){

case 1:

break ;

case 2:

// item name id 属性,并放入 map

String key=xpp.getAttributeValue( null , "name" );

String value=xpp.getAttributeValue( null , "id" );

map.put(key, value);

break ;

}

// 获得当前标签的属性个数

// int count = xml.getAttributeCount();

// 将所有属性的名称和属性值添加到 StringBuffer 对象中

// for (int i = 0; i < count; i++) {

// sb.append(xml.getAttributeName(i)

// + "xml.getAttributeValue(i)");

// }

}

// 标签结束状态

else if (eventType == XmlPullParser. END_TAG ) {

}

// 读取标签内容状态

else if (eventType == XmlPullParser. TEXT ) {

}

// 文档结束状态

else if (eventType == XmlPullParser. END_DOCUMENT ) {

// 文档分析结束后,退出 while 循环

break ;

}

// 切换到下一个状态,并获得当前状态的类型

eventType = xpp.next();

}

} catch (Exception e){

e.printStackTrace();

}

return map;

}

修改Activity调用代码:

String sXml = "<tqqk>" + "<item name=/" /" id=/"78/"/>"

+ "<item name=/" 多云 /" id=/"80/"/>"

+ "<item name=/" /" id=/"79/"/>"

+ "<item name=/" 小(阵)雨 /" id=/"4/"/>"

+ "<item name=/" 中雨 /" id=/"5/"/>"

+ "<item name=/" 大雨 /" id=/"802/"/>"

+ "<item name=/" 大到暴雨 /" id=/"7/"/>"

+ "<item name=/" 雷阵雨 /" id=/"181/"/>"

+ "<item name=/" 雨夹雪 /" id=/"84/"/>"

+ "<item name=/" 小雪 /" id=/"10/"/>"

+ "<item name=/" 中雪 /" id=/"11/"/>"

+ "<item name=/" 大到暴雪 /" id=/"83/"/>"

+ "<item name=/" 冰雹 /" id=/"13/"/>"

+ "<item name=/" /" id=/"14/"/>"

+ "<item name=/" 多云转晴 /" id=/"85/"/>"

+ "<item name=/" 阴湿 /" id=/"182/"/>"

+ "<item name=/" 闷热 /" id=/"202/"/>" + "</tqqk>" ;

ByteArrayInputStream stream = new ByteArrayInputStream(sXml.getBytes());

KVPsFromXml xml = new KVPsFromXml( this );

tqqk_map = xml.TqqkFromXml(stream, null );

Log.i ( "tqqk_map" , tqqk_map + "" );

现在我们构建了一个字符流传递给 TqqkFromXml 方法(第二个参数字符编码设定为null,因为java内部字符编码未发生任何改变),它仍然可以为我们读取xml的内容:

{大雨=802, 冰雹=13, 雷阵雨=181, 阴湿=182, =78, =79, 闷热=202, 多云=80, 雨夹雪=84, 小(阵)雨=4, 中雨=5, 小雪=10, 大到暴雨=7, 中雪=11, =14, 多云转晴=85, 大到暴雪=83}

当然,这里我偷了个懒,没有使用网络流读取xml,但结果不会有任何区别。

三、AttributeSet

XmlResourceParser还继承了AttributeSet接口。一个AttributeSet接口对象代表了一个Xml元素,它可以把该元素的所有属性用统一的方法进行访问。正如以下代码所示:

public Vector<Map<Object,Object>> getAttributeSet(String name){

Vector<Map<Object,Object>> vector= new Vector<Map<Object,Object>>();

// 获得处理 android xml 文件的 XmlResourceParser 对象

XmlResourceParser parser = ctx .getResources().getXml(

getResIDFromXmlFile(name));

int state = 0;

do {

// AttributeSet as;

try {

state = parser.next();

if (state == XmlPullParser. START_TAG && parser.getName().equals( "item" )) {

AttributeSet as=Xml.asAttributeSet (parser);

int n=as.getAttributeCount();

Map<Object,Object> map= new HashMap<Object,Object>();

while (n>0){

n--;

map.put(as.getAttributeName(n),as.getAttributeValue(n));

}

if (map!= null ) vector.add(map);

}

} catch (XmlPullParserException e1) {

e1.printStackTrace();

} catch (IOException e1) {

e1.printStackTrace();

}

} while (state != XmlPullParser. END_DOCUMENT );

return vector;

}

如你所见,AttributeSet接口实际上是一个抽象的对象,它并没有定义实例变量或字段,它只定义了一系列的访问Xml元素属性的方法,因此我们无法直接保存AttributeSet对象到集合中。最终我们把它复制到 Map 对象并放入集合中(因为我们的xml文件中有多个元素)。

接下来我们打印这些xml元素:

KVPsFromXml xml = new KVPsFromXml( this );

Vector<Map<Object,Object>> attrs=xml.getAttributeSet( "tqqk" );

for (Map<Object,Object> as : attrs){

Log.i ( "map" ,as.toString());

}

当然,Map 距离 Object 已经不远了,要将Map映射为对象只需要使用java的反射机制。

更多相关文章

  1. Android中style的使用
  2. Android(安卓)Fresco属性大全,中文说明
  3. listview原生态属性
  4. EditView某些属性说明
  5. Android中TextVIew一些属性
  6. View的状态属性简介
  7. activity属性设置大全
  8. Android(安卓)EditView属性
  9. Android中的布局

随机推荐

  1. Use twitter4j oauth to post status in
  2. android中的progressbar
  3. android异步任务完成后再执行主线程任务
  4. android 中的 ViewPager+ Fragment
  5. android中处理图片成圆角
  6. Android 解析字符乱码解决
  7. Android 添加系统设置属性
  8. Android AsyncTask 源码解析
  9. Android之Hello World
  10. 使用arm-eabi-addr2line, ndk-stack工具