Android SAX API: XmlResourceParser及其扩展应用

 

XmlResourceParser继承了2个接口:AttributeSet和XmlPullParser。其中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元素有两个属性:name和id。也就是说我们给每种天气定义一个名字和id。

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

现在我们需要用 XmlResourceParser 来读取xml文件并转换为KVP(key 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 SAX的 XMLPULL 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的反射机制。

 

转载于:https://www.cnblogs.com/encounter/archive/2011/05/23/2188489.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/378398.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux fdisk 磁盘空间使用率,linux查看磁盘剩余空间以及cpu使用情况

1、查看CPU个数cat /proc/cpuinfo | grep "physical id" | uniqtop可以实时的查看cpu的使用情况2、查看CPU核数cat /proc/cpuinfo | grep "cpu cores" | uniq3、查看CPU型号cat /proc/cpuinfo | grep model name |uniq4、查看内存cat /proc/meminfo | grep…

c语言 函数的参数传递示例_restder()函数,带有C ++中的示例

c语言 函数的参数传递示例C restder()函数 (C remainder() function) remainder() function is a library function of cmath header, it is used to calculate the remainder (IEC 60559), it accepts two parameters (numerator and denominator) and returns the remainder…

jquery validation-jquery的验证框架 详解(1)

jquery validation验证框架是一款非常优秀的客户端数据验证框架。我们在日常的项目中都会应用得到。今天开始我们会分两到三个个阶段 详细的了解这款插件 至于这款插件是多么的优秀&#xff0c;怎么个描述法 我这里就不详细述说。大家可以在接下来的时间里接触并且感觉它的强大…

已知一个掺杂了多个数字字符的中文名拼音,去掉所有数字字符之后,形式为“名”+空格+“姓”;并且名和姓的首字母大写,其他小写,要求输出姓名全拼,且全为小写。(后附详细样例说明)

已知一个掺杂了多个数字字符的中文名拼音&#xff0c;去掉所有数字字符之后&#xff0c;形式为“名”空格“姓”&#xff1b;并且名和姓的首字母大写&#xff0c;其他小写&#xff0c;要求输出姓名全拼&#xff0c;且全为小写。&#xff08;后附详细样例说明&#xff09; 【输入…

【视觉项目】【day2】8.21号实验记录(手机固定高度15cm拍摄+直方图均衡化+模板匹配,模板12个,测试28个,效果十分差)

目录均衡化代码模板图片按照大小排序总代码测试效果新思路由于模板匹配是像素之间的比对&#xff0c;所以不同光照下的像素灰度值也会不同 所以在比对之前&#xff0c;我们需要对测试图和模板图进行直方图均衡化&#xff0c;这一步可以先实现。 今天将采用批量处理的方式&#…

c语言 函数的参数传递示例_isgreater()函数以及C ++中的示例

c语言 函数的参数传递示例C isgreater()函数 (C isgreater() function) isgreater() function is a library function of cmath header, it is used to check whether the given first value is greater than the second value. It accepts two values (float, double or long…

在一个风景秀丽的小镇,一天早上,有N名晨跑爱好者(编号1~N)沿着优雅的江边景观道朝同一方向进行晨跑

【问题描述】 在一个风景秀丽的小镇&#xff0c;一天早上&#xff0c;有N名晨跑爱好者(编号1~N)沿着优雅的江边景观道朝同一方向进行晨跑&#xff0c;第i名跑者从位置si处起跑&#xff0c;且其速度为Vi。换句话说&#xff0c;对所有的实数t≥0&#xff0c;在时刻t时第i名跑者的…

linux内核测试,Linux内核测试的生命周期

内核持续集成(CKI)项目旨在防止错误进入 Linux 内核。在 Linux 内核的持续集成测试 一文中&#xff0c;我介绍了 内核持续集成Continuous Kernel Integration(CKI)项目及其使命&#xff1a;改变内核开发人员和维护人员的工作方式。本文深入探讨了该项目的某些技术方面&#xff…

Linux下动态库使用小结

1. 静态库和动态库的基本概念 静态库&#xff0c;是在可执行程序连接时就已经加入到执行码中&#xff0c;在物理上成为执行程序的一部分&#xff1b;使用静态库编译的程序运行时无需该库文件支持&#xff0c;哪里都可以用&#xff0c;但是生成的可执行文件较大。动态库&#xf…

【视觉项目】【day3】8.22号实验记录(利用canny检测之后的来进行模板匹配)

【day3】8.22号实验记录&#xff08;几乎没干正事的一天&#xff0c;利用canny检测之后的来进行模板匹配&#xff09; 今天没搞代码&#xff0c;主要是问研究生学长工业摄像头的接法的&#xff0c;学长也不知道&#xff0c;明天问问老师。。。 晚上搞了一下canny之后的模板匹配…

scala字符替换_如何替换Scala中的“坏”字符?

scala字符替换In Scala, programming language, all sorts of special characters are valid. The character set library is quite good and supports almost all characters in Scala programming. 在编程语言Scala中&#xff0c;各种特殊字符均有效。 字符集库非常好&#x…

linux dd 大文件下载,Linux dd+grep 大文件二分查找

Linux dd 命令用于读取、转换并输出数据。dd 可从标准输入或文件中读取数据&#xff0c;根据指定的格式来转换数据&#xff0c;再输出到文件、设备或标准输出。参数说明(dd --help)Usage: dd [OPERAND]...or: dd OPTIONCopy a file, converting and formatting according to th…

【视觉项目】【day1】8.20号实验记录(初步使用模板匹配)

目录【day1】8.20号实验记录&#xff08;初步使用模板匹配&#xff09;模板匹配单张图的代码利用多个模板去匹配多张图的代码写代码过程中遇到的问题【day1】8.20号实验记录&#xff08;初步使用模板匹配&#xff09; 模板匹配 利用模板匹配可以框定出瓶子&#xff0c;但是却…

第四章 纤维结构对染色性能的影响单元测验

1,利用红外光谱技术可以测定纤维的() 化学结构。 2,纤维完整的结构包括() 化学结构。 表面形态结构。 内部超分子结构。 3,纤维化学结构由于影响了纤维(),进而影响其染色性能 吸湿溶胀性能。 在染液中电离性能。 在染浴中的带电性。 与染液中各组分之间的作用力。 …

创建存储过程时出现的This function has none of DETERMINISTIC, NO SQL解决办法

This function has none of DETERMINISTIC, NO SQL解决办法创建存储过程时 出错信息&#xff1a; ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the …

如何让没有安装网页中所需字体的用户也能得到一致的浏览效果【转】

今天给大家谈一个关于字体的话题,我们在做项目的过程中会遇到一些在psd中的字体在自己的电脑中没有安装&#xff0c;或者是一些特殊的文字&#xff0c;通常的做法是把它切成图片&#xff0c;但是如果这个站是多个语言的&#xff0c;那我们是不是把每个语言的都切一张图片呢&…

【视觉项目】【day4】8.24号实验记录(消除瓶子内部“边缘”)

思路分析以及代码 思路1&#xff1a;使用findContours函数&#xff0c;设置轮廓为最外部RETR_EXTERNAL&#xff0c;结果发现结果仍然是所有轮廓。 思路2&#xff1a;先二值化&#xff0c;然后进行闭操作&#xff0c;然后canny&#xff0c;得到的轮廓确实比之前少很多&#xff…

operator.ne_Python operator.ne()函数与示例

operator.neoperator.ne()函数 (operator.ne() Function) operator.ne() function is a library function of operator module, it is used to perform "not equal to operation" on two values and returns True if the first value is not equal to the second val…

国产操作系统和linux 之间的关系,为何国产系统大多基于开源Linux?操作系统从0做起到底有多难?...

今年貌似是国产操作系统的“爆发”之年&#xff0c;除了老牌的银河麒麟、中标麒麟、深度之外&#xff0c;中兴近日发布了自己的“新支点”&#xff0c;华为也公开了自研的操作系统“鸿蒙”。纵观这些国产操作系统&#xff0c;大多基于开源的Linux。那么为什么我们不可以从0开始…

away3d创建基础view世界(基础 一)

对于away3d可能很多人有畏惧心里&#xff0c;其实away3d没有想象中的那么难&#xff0c;现在我就教大家创建一个简单的view世界。 package{import away3d.containers.View3D;import flash.display.Sprite;public class Main extends Sprite{private var view:View3D;//兴建一个…