Android开发必备武器,处理XML的利器——SAX快速上手

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
云解析DNS,个人版 1个月
简介:   相信各位android开发者,对SAX已经并不陌生了,SAX(Simple API for XML),是一个使用非常广泛的XML解析标准,通常使用Handler模式来处理XML文档,这种处理模式和我们平常习惯的理解方式很不同,身边也经常有一些朋友在刚接触SAX的时候会觉得理解起来有些困难。

  相信各位android开发者,对SAX已经并不陌生了,SAX(Simple API for XML),是一个使用非常广泛的XML解析标准,通常使用Handler模式来处理XML文档,这种处理模式和我们平常习惯的理解方式很不同,身边也经常有一些朋友在刚接触SAX的时候会觉得理解起来有些困难。其实SAX并不复杂,只不过是换了一种思维方式,正如它的名字所表示的,为了让我们以更简单的方式来处理XML文档,下面我们就开始吧。
      我们通常的理解方式是,我们给出一个输入(比如xml文档的地址),然后程序返回给我们数据(比如解析后的xml文档结构),我们在返回给我们的结果中进行相应的操作,而SAX以一种更简单的方式来处理XML文档的解析,也就是处理器模式,一个使用SAX的简单示例:

 
 
1 SAXParserFactory spf = SAXParserFactory.newInstance();
2 SAXParser sp = spf.newSAXParser();
3 XMLReader reader = sp.getXMLReader();
4
5
6 reader.setContentHandler(myHandler);
7 reader.parse( new InputSource( new URL(url).openStream()));

     正如上面的代码,我们使用一系列工厂方法生成了一个XMLReader对象,随后,最关键的一行就是reader.setContentHandler,这里为这个reader设置了一个处理器,这个处理器的具体内容是要我们来完成的,稍后会详细介绍,最后调用parse方法完成文档的解析。这是SAX的一个基本流程。
     下面我们来详细介绍一下处理器,SAX处理器使用的是一种和我们平时的理解方式不太一样的处理形式,是在遍历文档的同时,让我们来进行文档的处理。     用一个实际的例子来解释更为方便,假如有下面这样一个XML文档:

 
 
1 < student >
2 < name > 张三 </ name >
3 < age > 22 </ age >
4 < sn > 1001 </ sn >
5   </ student >
6   < student >
7 < name > 李四 </ name >
8 < age > 21 </ age >
9 < sn > 1002 </ sn >
10   </ student >

      使用SAX的时候,解析器会对XML文档进行深度优先遍历,在遍历的时候,会根据条件调用处理器中的方法,如上面的XML文档,首先会遍历到第一个student的起始节点,这时我们可以在处理器中进行一些需要的处理,随后会分别遍历name,age,sn起始节点和结束节点,以此类推,这样说起来可能还不够直观,下面我们就来看看一个处理器的基本结构:

 
 
1 public class MyHandler extends DefaultHandler {
2
3 public void startElement(String uri, String localName, String qName,
4 }
5
6 public void endElement(String uri, String localName, String qName)
7 throws SAXException {
8 }
9
10 public void characters( char [] ch, int start, int length)
11 throws SAXException {
12 }
13 }

      如上面的代码,这里有几个比较重要的方法,startElement是进入到起始节点的时候会调用的方法,例如上面的xml文件,进入到<student>节点时,就会调用startElement方法。     endElement方法,在结束一个节点的时候会调用,例如进入到</student>节点时,该方法会被调用。     characters方法,在进入XML节点的文本节点(TextNode)时会被调用,例如<name>张三</name>,在便利到‘张三’这个文本节点的时候,这个方法会被调用。
     另外还有两个回调方法,分别为startDocument,endDocument,顾名思义,这两个方法为进入文档和离开文档时要调用的方法。

     下面我们就来自己写一个处理器来解析上面的XML文档。首先我们需要将每个节点封装成一个实体对象:

 
 
1 public class Student {
2 private String name;
3
4 private int age;
5
6 private String sn;
7 public String getName() {
8 return name;
9 }
10 public void setName(String name) {
11 this .name = name;
12 }
13 public int getAge() {
14 return age;
15 }
16 public void setAge( int age) {
17 this .age = age;
18 }
19 public String getSn() {
20 return sn;
21 }
22 public void setSn(String sn) {
23 this .sn = sn;
24 }
25
26
27 }
28  

     下面再来完成处理器的代码:

 
 
1 public class MyHandler extends DefaultHandler {
2
3 private List < Student > studentList;
4
5 private boolean inStudent = false ;
6
7 private boolean studentName = false ;
8
9 private boolean studentAge = false ;
10
11 private boolean studentSN = false ;
12
13 private Student curStudent ;
14
15 public MyHandler() {
16
17 studentList = new ArrayList < Student > ();
18 }
19 @Override
20 public void startElement(String uri, String localName, String qName,
21 Attributes attributes) throws SAXException {
22
23 String tagName = localName.length() != 0 ? localName : qName;
24 tagName = tagName.toLowerCase().trim();
25
26 if (tagName.equals( " student " )) {
27 inStudent = true ;
28 curStudent = new Student();
29 }
30
31 if (inStudent) {
32
33 if (tagName.equals( " name " )) {
34 studentName = true ;
35 } else if (tagName.equals( " age " )) {
36 studentAge = true ;
37 } else if (tagName.equals( " sn " )) {
38 studentSN = true ;
39 }
40 }
41
42 }
43
44 @Override
45 public void endElement(String uri, String localName, String qName)
46 throws SAXException {
47
48 String tagName = localName.length() != 0 ? localName : qName;
49 tagName = tagName.toLowerCase().trim();
50
51 if (tagName.equals( " student " )) {
52 inStudent = true ;
53 studentList.add(curStudent);
54 }
55
56 if (inStudent) {
57
58 if (tagName.equals( " name " )) {
59 studentName = false ;
60 } else if (tagName.equals( " age " )) {
61 studentAge = false ;
62 } else if (tagName.equals( " sn " )) {
63 studentSN = false ;
64 }
65 }
66 }
67
68 @Override
69 public void characters( char [] ch, int start, int length)
70 throws SAXException {
71
72 if (studentName) {
73 curStudent.setName(curStudent.getName() + new String(ch,start,length));
74 } else if (studentAge) {
75 curStudent.setAge(Integer.parseInt( new String(ch,start,length)));
76 } else if (studentSN) {
77 curStudent.setSn(curStudent.getSn() + new String(ch, start, length));
78 }
79 }
80 }
81  

  如上面的代码,我们使用了一系列的布尔标志变量来保存文档的遍历状态,先从startElement说起,当我们进入到student节点的时候,我们将inStudent状态设置为true,表示我们已经处于student节点之中,同时创建了一个student对象,相应地,在endElement方法中,我们遇到student结束的时候,会把这个对象添加到我们的studentList中,并将inStudent状态设置为false。同样的,在startElement方法中判断instudent状态,如果当前已经处于student节点中,并且遍历到name,age或者sn节点时,我们也将相应的标志设置为true。这样在遍历的文本节点的时候就可以在characters方法中通过判断这些标志位来为Student对象设置相应的属性。
  注意到,这里curStudent.setName(curStudent.getName() + new String(ch,start,length)),我们用以前的值和新的值连接起来,而不是直接设置curStudent.setName(new String(ch,start,length))。这是因为在遍历<name>.....</name>这中间的文本节点的时候,有些时候这对标签中的内容可能会被看做多个文本节点,比如包含Html实体的情况下 <name>张 三</name>,这里相当于包含了两个文本节点,如果不使用连接的方式而采用直接设置的方式,那么我们最终只能得到最后一次设置的值,因为前面设置的被覆盖了。那么我们最终取得到的名字就是‘三’了。
    这个处理器的核心分功能就算完成了,下面我们还需要增加一个方法,用来返回处理后的内容:

 
 
1 public List < Student > getStudentList() {
2 return studentList;
3 }

  完成了处理器之后,我们就可以用刚开始介绍的方法来解析XML文档了:

 
 
1 SAXParserFactory spf = SAXParserFactory.newInstance();
2 SAXParser sp = spf.newSAXParser();
3 XMLReader reader = sp.getXMLReader();
4
5 List < Student > list;
6 reader.setContentHandler(myHandler);
7 reader.parse( new InputSource( new URL(url).openStream()));
8
9 list = myHandler.getStudentList();

     可以看到,解析完XML文档之后,我们就可以用处理器重的getStudentList方法取得解析后的数据了。
     最后总结一下,SAX并不复杂,只要理解了它的思维方式,我们就可以游刃有余,使它成为我们开发的利器,这篇文章向大家介绍了SAX的一些基本知识,希望能起到一个抛砖引玉的作用,大家能够使用它来创造出更多好的应用,当然可能有一些地方解释的还不是十分完美,如果有一些不好理解的地方,还望大家指出。
     另外下面是SAX的一个官方网站,里面有一些介绍和代码示例,英文不错的童鞋可以来这里参考一下:http://www.saxproject.org

目录
相关文章
|
4天前
|
Java Android开发 iOS开发
探索安卓与iOS开发的差异性与互操作性
【7月更文挑战第17天】在移动应用开发的广阔天地中,安卓和iOS这两大操作系统如同双子星座般璀璨夺目。它们各自拥有独特的开发环境、编程语言和用户群体,为开发者提供了不同的挑战和机遇。本文将从多个维度深入剖析安卓与iOS开发的差异性,并探讨它们之间的互操作性如何实现,以期为开发者们提供一份实用的指南。
16 7
|
2天前
|
Java Android开发 Swift
探索iOS与安卓开发的差异与挑战
本文深入探讨了iOS和安卓两大移动操作系统在应用开发领域的不同点及其所面临的挑战。通过对开发环境、编程语言、用户界面设计、性能优化及市场策略的比较分析,揭示了各自平台的独特性以及开发者需要克服的技术与市场障碍。 【7月更文挑战第19天】
|
2天前
|
Java Android开发 iOS开发
探索安卓与iOS开发的差异:平台特性与用户体验的对比分析
【7月更文挑战第19天】在移动开发的广阔天地中,安卓与iOS两大阵营各据一方,它们在开发环境、用户界面设计、性能优化等方面展现出独特的魅力与挑战。本文旨在深入探讨这两个平台在技术开发和用户体验上的根本差异,并分析这些差异如何影响开发者的策略和最终用户的选择。通过比较两者的编程语言、工具、框架以及设计理念,我们将揭示各自平台的优势与局限,为开发者提供实用的参考,并为消费者呈现一个更加清晰的平台选择视角。
|
3天前
|
安全 Java Android开发
探索安卓与iOS开发的差异:构建未来应用的关键考量
【7月更文挑战第18天】在移动应用开发的广阔天地中,安卓和iOS两大平台各领风骚。本文将深入探讨这两个平台在开发过程中的主要差异,包括编程语言、用户界面设计、性能优化、安全性以及市场策略等方面。通过比较分析,旨在为开发者提供决策支持,帮助他们选择最适合自己项目需求的平台,同时考虑到用户体验和市场需求的变化,为未来的应用开发指明方向。
|
4天前
|
监控 开发工具 Android开发
探索安卓与iOS开发的差异:平台特性、工具和市场趋势
在移动应用开发的广阔舞台上,安卓与iOS两大操作系统扮演着主角。它们各自拥有独特的平台特性、开发工具和市场定位,这些差异深刻影响着开发者的决策和产品的最终形态。本文将深入分析这两大平台的关键技术差异,探讨各自的开发环境和工具集,以及它们在市场上的表现和未来的趋势,为开发者提供一个全面的视角,帮助他们在这两个平台上做出更明智的开发选择。
|
1天前
|
开发工具 Android开发 Swift
探索Android与iOS开发的差异与挑战
【7月更文挑战第20天】在移动应用开发的广阔天地中,Android和iOS两大平台如同双子星座,各自闪耀着独特的光芒。本文将深入探讨这两个平台在开发过程中的主要差异,以及开发者面临的技术挑战。我们将从开发环境、编程语言、用户界面设计、性能优化、安全性考量等多个维度展开讨论,旨在为那些即将踏入或已在这片星空下航行的开发者提供一盏明灯。
|
2天前
|
Java Android开发 iOS开发
探索安卓与iOS开发的差异:平台特性与用户体验的对比分析
在移动应用开发的广阔天地中,安卓与iOS两大阵营各自占据着半壁江山。本文将深入探讨这两个平台在开发环境、编程语言、用户界面设计以及性能优化方面的差异,并分析这些差异如何影响最终的用户体验。通过数据支持的案例分析和最新的市场研究,我们将揭示开发者如何在这两个不同的生态系统中做出战略决策,以及这些决策对应用成功的潜在影响。
|
26天前
|
XML Java 数据格式
java创建xml文件内容
java创建xml文件内容
19 0
|
26天前
|
XML Java 数据格式
java解析xml文件内容
java解析xml文件内容
22 0
|
22天前
|
XML Java 数据库
配置applicationContext.xml文件
配置applicationContext.xml文件