Android XML解析学习——Sax方式(续) .

来源:互联网 发布:程序数据和相应的文档 编辑:程序博客网 时间:2024/05/12 09:21

图1 ListView列表显示的地震数据

 

和上一部分Demo例子的一样,也是解析完地震数据后用ListView列表的方式显示每条地震的震级和地名信息。

新建一个Android工程AndroidXMLDemoSaxII。

添加进上一个Demo工程AndroidXMLDemoSax中的EarthquakeEntry.java文件,如果需要从本地读取xml数据的话,同时在assets文件夹下添加保存为xml格式了的USGS地震数据USGS_Earthquake_1M2_5.xml,如果需要联网读取的话,在manifest.xml文件中添加权限:

 

[java] view plaincopyprint?
  1. <uses-permission android:name="android.permission.INTERNET" />  

并修改res/layout下的main.xml为:

 

[xhtml] view plaincopyprint?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent"  
  6.     >  
  7.   <ListView  
  8.     android:id="@+id/list"  
  9.     android:layout_width="fill_parent"   
  10.     android:layout_height="fill_parent"  
  11.   />  
  12. </LinearLayout>  

 

接下来就来新建添加一个类AndroidSaxEarthquakeHandler,以Android SDK提供的包android.sdkAPI完成解析地震数据的具体逻辑实现,内容如下:

 

[java] view plaincopyprint?
  1. public class AndroidSaxEarthquakeHandler {  
  2.     //xml解析用到的Tag   
  3.     private String kRootElementName = "feed";  
  4.     private String kEntryElementName = "entry";  
  5.     private String kLinkElementName = "link";  
  6.     private String kTitleElementName = "title";  
  7.     private String kUpdatedElementName = "updated";  
  8.     private String kGeoRSSPointElementName = "point";  
  9.     private String kGeoRSSElevElementName = "elev";  
  10.     static final String ATOM_NAMESPACE = "http://www.w3.org/2005/Atom";   
  11.     static final String GEORSS_NAMESPACE = "http://www.georss.org/georss";  
  12.     //用于保存xml解析获取的结果   
  13.     private ArrayList<EarthquakeEntry> earthquakeEntryList;  
  14.     private EarthquakeEntry earthquakeEntry;  
  15.       
  16.     //解析xml数据   
  17.     public ArrayList<EarthquakeEntry> parse(InputStream inStream)  
  18.     {  
  19.         earthquakeEntryList = new ArrayList<EarthquakeEntry>();  
  20.         RootElement root = new RootElement(ATOM_NAMESPACE, kRootElementName);  
  21.         Element entry = root.getChild(ATOM_NAMESPACE, kEntryElementName);  
  22.         //具体解析xml   
  23.         //处理entry标签   
  24.         entry.setStartElementListener(new StartElementListener() {        
  25.             @Override  
  26.             public void start(Attributes attributes) {  
  27.                 // TODO Auto-generated method stub   
  28.                 earthquakeEntry = new EarthquakeEntry();  
  29.             }  
  30.         });  
  31.         entry.setEndElementListener(new EndElementListener() {    
  32.             @Override  
  33.             public void end() {  
  34.                 // TODO Auto-generated method stub   
  35.                 earthquakeEntryList.add(earthquakeEntry);  
  36.             }  
  37.         });  
  38.         //处理title标签   
  39.         entry.getChild(ATOM_NAMESPACE, kTitleElementName).setEndTextElementListener(new EndTextElementListener() {  
  40.             @Override  
  41.             public void end(String currentData) {  
  42.                 // TODO Auto-generated method stub   
  43.                 //提取强度信息   
  44.                 String magnitudeString = currentData.split(" ")[1];  
  45.                 int end =  magnitudeString.length()-1;  
  46.                 magnitudeString = magnitudeString.substring(0, end);  
  47.                 double magnitude = Double.parseDouble(magnitudeString);  
  48.                 earthquakeEntry.setMagnitude(magnitude);  
  49.                 //提取位置信息   
  50.                 String place = currentData.split(",")[1].trim();  
  51.                 earthquakeEntry.setPlace(place);                  
  52.             }  
  53.         });  
  54.         //处理updated标签   
  55.         entry.getChild(ATOM_NAMESPACE, kUpdatedElementName).setEndTextElementListener(new EndTextElementListener() {  
  56.             @Override  
  57.             public void end(String currentData) {  
  58.                 // TODO Auto-generated method stub   
  59.                 //构造更新时间   
  60.                 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");  
  61.                 Date qdate = new GregorianCalendar(0,0,0).getTime();  
  62.                 try {  
  63.                   qdate = sdf.parse(currentData);  
  64.                 } catch (ParseException e) {  
  65.                   e.printStackTrace();  
  66.                 }  
  67.                 earthquakeEntry.setDate(qdate);               
  68.             }  
  69.         });  
  70.         //处理point标签   
  71.         entry.getChild(GEORSS_NAMESPACE, kGeoRSSPointElementName).setEndTextElementListener(new EndTextElementListener() {    
  72.             @Override  
  73.             public void end(String currentData) {  
  74.                 // TODO Auto-generated method stub   
  75.                 //提取经纬度信息   
  76.                 String[] latLongitude = currentData.split(" ");  
  77.                 Location location = new Location("dummyGPS");  
  78.                 location.setLatitude(Double.parseDouble(latLongitude[0]));  
  79.                 location.setLongitude(Double.parseDouble(latLongitude[1]));  
  80.                 earthquakeEntry.setLocation(location);  
  81.             }  
  82.         });  
  83.         //处理elev标签   
  84.         entry.getChild(GEORSS_NAMESPACE, kGeoRSSElevElementName).setEndTextElementListener(new EndTextElementListener() {  
  85.             @Override  
  86.             public void end(String currentData) {  
  87.                 // TODO Auto-generated method stub   
  88.                 //提取海拔高度信息   
  89.                 double evel;  
  90.                 //因为USGS数据有可能会输错,比如为"--10000",多了一个"-"号   
  91.                 try {  
  92.                     evel = Double.parseDouble(currentData);  
  93.                 } catch (Exception e) {  
  94.                     // TODO: handle exception   
  95.                     e.printStackTrace();  
  96.                     evel = 0;  
  97.                 }  
  98.                 Log.v("Sax_Elev", String.valueOf(evel));  
  99.                 earthquakeEntry.setElev(evel);            
  100.             }  
  101.         });  
  102.         //处理link标签   
  103.         entry.getChild(ATOM_NAMESPACE, kLinkElementName).setStartElementListener(new StartElementListener() {         
  104.             @Override  
  105.             public void start(Attributes attributes) {  
  106.                 // TODO Auto-generated method stub   
  107.                 //获取link链接   
  108.                 String webLink = attributes.getValue("href");  
  109.                 earthquakeEntry.setLink(webLink);  
  110.             }  
  111.         });  
  112.         //调用android.util.Xml开始解析   
  113.         try {  
  114.             Xml.parse(inStream, Xml.Encoding.UTF_8, root.getContentHandler());  
  115.         } catch (Exception e) {  
  116.             // TODO Auto-generated catch block   
  117.             e.printStackTrace();  
  118.         }  
  119.           
  120.         return earthquakeEntryList;  
  121.     }  
  122. }  

 

开头处定义了解析需要的元素标签名称,因为getChild方法获取子元素时需要命名空间,因此还新定义了USGSxml数据中包含的两个命名空间:

 

[java] view plaincopyprint?
  1. static final String ATOM_NAMESPACE = "http://www.w3.org/2005/Atom";   
  2. static final String GEORSS_NAMESPACE = "http://www.georss.org/georss";  

在定义的用于解析xml数据的方法中

public ArrayList<EarthquakeEntry>parse(InputStream inStream)

首先获取xml文档的根元素:

RootElement root = new RootElement(ATOM_NAMESPACE,kRootElementName);

有了根元素之后,就可以使用类似DOMgetChild方法获取具体的某个位置处的子元素,并且可以为具体的子元素注册事件处理器和在对应的回调函数中实现具体的处理逻辑。

从程序中我们可以看到,我们只为<entry>元素和<entry></entry>包含的子元素注册了事件处理器,因此即使xml文档开始处有<updated>、<title>和<link>等同名的元素标签,但也不会进行处理。因此和上一部分的Demo相比,就不再需要设置标志变量用来判断,而且看起来也更加简单了。

虽然写法不同了,但是对具体标签的处理逻辑和上一部分Demo中是一样的,因为处理的xml文档内容没有变。

程序的最后调用android.util.Xml类的类方法parse直接进行解析,也更加方便了。

 

[java] view plaincopyprint?
  1. //调用android.util.Xml开始解析   
  2.     try {  
  3.         Xml.parse(inStream, Xml.Encoding.UTF_8, root.getContentHandler());  
  4.     } catch (Exception e) {  
  5.         // TODO Auto-generated catch block   
  6.         e.printStackTrace();  
  7.     }  

其中Xmlparse方法的ContentHandler参数由根元素通过getContentHandler()方式获得。

最后添加AndroidXMLDemoSaxII.java文件中的内容,内容和上一个Demo工程AndroidXMLDemoSax中的AndroidXMLDemoSax.java基本一样,

[java] view plaincopyprint?
  1. public class AndroidXMLDemoSaxII extends Activity {  
  2.     /** Called when the activity is first created. */  
  3.     //定义显示的List相关变量   
  4.     ListView list;  
  5.     ArrayAdapter<EarthquakeEntry> adapter;  
  6.     ArrayList<EarthquakeEntry> earthquakeEntryList;  
  7.     @Override  
  8.     public void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.main);  
  11.           
  12.         //获取地震数据流   
  13.         InputStream earthquakeStream = readEarthquakeDataFromFile();  
  14.         //Android Sax方式进行解析   
  15.         AndroidSaxEarthquakeHandler androidSaxHandler = new AndroidSaxEarthquakeHandler();  
  16.         earthquakeEntryList = androidSaxHandler.parse(earthquakeStream);  
  17.         //用ListView进行显示   
  18.         list = (ListView)this.findViewById(R.id.list);  
  19.         adapter = new ArrayAdapter<EarthquakeEntry>(this, android.R.layout.simple_list_item_1, earthquakeEntryList);  
  20.         list.setAdapter(adapter);  
  21.     }  
  22.       
  23.     private InputStream readEarthquakeDataFromFile()  
  24.     {  
  25.         //从本地获取地震数据   
  26.         InputStream inStream = null;  
  27.         try {  
  28.             inStream = this.getAssets().open("USGS_Earthquake_1M2_5.xml");  
  29.         } catch (IOException e) {  
  30.             // TODO Auto-generated catch block   
  31.             e.printStackTrace();  
  32.         }  
  33.         return inStream;  
  34.     }  
  35.     private InputStream readEarthquakeDataFromInternet()  
  36.     {  
  37.         //从网络上获取实时地震数据   
  38.         URL infoUrl = null;  
  39.         InputStream inStream = null;  
  40.         try {  
  41.             infoUrl = new URL("http://earthquake.usgs.gov/earthquakes/catalogs/1day-M2.5.xml");  
  42.             URLConnection connection = infoUrl.openConnection();  
  43.             HttpURLConnection httpConnection = (HttpURLConnection)connection;  
  44.             int responseCode = httpConnection.getResponseCode();  
  45.             if(responseCode == HttpURLConnection.HTTP_OK)  
  46.             {  
  47.                 inStream = httpConnection.getInputStream();  
  48.             }  
  49.         } catch (MalformedURLException e) {  
  50.             // TODO Auto-generated catch block   
  51.             e.printStackTrace();  
  52.         } catch (IOException e) {  
  53.             // TODO Auto-generated catch block   
  54.             e.printStackTrace();  
  55.         }  
  56.         return inStream;  
  57.     }  
  58. }  

 

 

只是把进行SAX解析的部分换成了如下方式:

[java] view plaincopyprint?
  1. //Android Sax方式进行解析   
  2. AndroidSaxEarthquakeHandler androidSaxHandler = new AndroidSaxEarthquakeHandler();  
  3. earthquakeEntryList = androidSaxHandler.parse(earthquakeStream);  
 

完成了,可以保存运行看下效果。

 

三.总结

Android平台提供了相当强大的XML解析支持,不仅包含了Java SDK中用来XML处理的API,而且Android SDK还提供了特有的用于SAX解析XML的包android.sax。使用这个包中的API可以更加方便解析,特别是当要解析的xml文档中在不同的层级位置处有多个相同名称的标签但需要分别进行不同处理时,同时也有更好的鲁棒性,减少解析时产生Bug的可能性。

以上我们介绍的都是SAX方式解析XML,而解析XML常用的还有DOM方式,这部分内容我们以后接着学习