zoukankan      html  css  js  c++  java
  • 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的反射机制。

  • 相关阅读:
    AFNetWorking网络库教程
    安卓教程
    HTML5学习教程
    PHP学习教程汇总
    关于cocos2d-x 诸类的详解
    cocos2d-x 学习资料(很全)
    关于IOS开发知识的总结
    叶子效果
    ios后台下载
    ios中webservice报文的拼接
  • 原文地址:https://www.cnblogs.com/encounter/p/2188489.html
Copyright © 2011-2022 走看看