Xml解析之——Java/Android/Python

一、Xml文件 test.xml

1

2 George

3 John

4 Reminder

5

Don't forget the meeting!


6

7 fetch="."

8 review="gerrit.huaqin.com:8081" />

9

10 remote="origin"

11 sync-j="4" />

12

上面是一个简单的xml文件,个人的理解:xml文件是一个格式标准,代码清晰的树形结构体。

二、Xml文件的解析

xml解析主要是有SAX和DOM ,python还另外提供了ElementTree(轻量级的DOM),android提供了PULL。

简单的介绍下集中解析方式

DOM:将整个XML文件解析到内存生成一个树形结构。

优点:整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能;缺点:将整个文档调入内存(包括无用的节点),浪费时间和空间;

适用点:对象传输,全文件的数据修改等

SAX:基于事件驱动的,也就是说解析器去从xml文件的开始往下走,当发现元素开始、元素结束、文本、文档的开始或结束等时,发送事件,程序员编写响应这些事件的代码,保存数据。

优点:不用事先调入整个文档,占用资源少

适用点:元素检索

PULL:运行方式和SAX类似,基于事件的模式。不同的是,在PULL解析过程中,我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器。

三、例子

我们就以操作test.xml为例。

1.DOM(python实现)

1 __author__ = 'xuqiang'

2 from xml.dom importminidom,Node3

4 #先将文件解析出来放在DOMTree中

5 DOMTree = minidom.parse("test.xml")6 #取根节点

7 note =DOMTree.documentElement8 length =len(note.childNodes)9 #依次取子节点

10 for child innote.childNodes:11 if child.nodeType ==Node.COMMENT_NODE:12 print child.name + ':' +child.nodeValue13 elif child.nodeType ==Node.ELEMENT_NODE:14 print "" %child.nodeName15 #取子就子节点属性

16 ifchild.hasAttributes():17 attributes =child.attributes18 for index inrange(attributes.length):19 print "%s = %s" %(attributes.item(index).name,attributes.item(index).value)20 #去子节点的文本

21 ifchild.hasChildNodes():22 print "%s" %child.childNodes[0].data23 print "%s>" % child.nodeName

2.SAX

SAX最佳使用的地方就是查找某个元素的值

假设我们要取test.xml中字节点remote的属性name的值

1 __author__ = 'xuqiang'

2

3 importxml4 importxml.sax5

6 classTestHandler(xml.sax.ContentHandler):7 def __init__(self):8 self.to = ""

9 self.fromm = ""

10 self.heading = ""

11 self.body = ""

12 self.review = ""

13 self.name = ""

14 self.fetch = ""

15 self.remote = ""

16 self.defaultremote = ""

17 self.sync = ""

18 self.revision = ""

19 self.default = ""

20

21 defstartElement(self, tag, attributes):22 self.CurrentData =tag23 #找到节点remote的属性 name

24 if tag == 'remote':25 print "remote name is %s" % attributes.get('name')26

27 defendElement(self, tag):28 if self.CurrentData == "to":29 print "to:", self.to30 elif self.CurrentData == "from":31 print "from:", self.fromm32 elif self.CurrentData == "heading":33 print "heading:", self.heading34 elif self.CurrentData == "body":35 print "body:", self.body36 elif self.CurrentData == "remote":37 print "remote:", self.remote38 elif self.CurrentData == "default":39 print "default:", self.default40 self.CurrentData = ""

41

42 defcharacters(self, content):43 if self.CurrentData == "to":44 self.to =content45 elif self.CurrentData == "from":46 self.fromm =content47 elif self.CurrentData == "heading":48 self.heading =content49 elif self.CurrentData == "body":50 self.body =content51 elif self.CurrentData == "remote":52 self.remote =content53 elif self.CurrentData == "default":54 self.default =content55

56 parser =xml.sax.make_parser()57 parser.setFeature(xml.sax.handler.feature_namespaces, 0)58 Handler =TestHandler()59 parser.setContentHandler(Handler)60 parser.parse("test.xml")

DOM和SAX是最常见的解写xml的方式,这里python实现,java的实现基本差别不大

三、PULL

PULL是android中最常用的解析xml的方式。他的原理和SAX类似,是基于事件处理的。使用方法也类似。

我们以谷歌天气为例,这是我们从google官方网站上下载下来的xml格式的当天天气。

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

2

3

4

5 CN

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

xml文件中参数比较多,我现在只想知道城市,温度,适度,风向四个值,建立一个数据结构CurrentWeatherXml来保存这四个值

1 packageorg.xerrard.xmlpulldemo;2

3 public classCurrentWeatherXml {4

5

6 public String city; //城市

7 public String temperature; //温度

8 public String humidity; //湿度

9 public String wind_direction; //风向

10

11 publicString toString()12 {13 //摄氏度(℃)=K-273。

14 float s =Float.parseFloat(temperature);15 float temperatureC = s-273;16

17 StringBuilder sb = newStringBuilder();18 sb.append(" 城市: ").append(city);19 sb.append(" 天气: ").append(temperature + "").append(" °K");20 sb.append(" 天气: ").append(temperatureC + "").append(" °C");21 sb.append(" 湿度 ").append(humidity);22 sb.append(" 风向 ").append(wind_direction);23 returnsb.toString();24 }25 }

我们建立一个Model类来做xml的处理,在这个类中,我们对xml文件进行解析,从中抽取城市,天气,湿度,风向,并将其值存入到CurrentWeatherXml中

1 packageorg.xerrard.xmlpulldemo;2

3 importjava.io.InputStream;4

5 importorg.xmlpull.v1.XmlPullParser;6 importorg.xmlpull.v1.XmlPullParserFactory;7

8 importandroid.util.Log;9

10 public classWeatherXMLModel {11

12 public static CurrentWeatherXml curCondition = null;13

14 public static voidinitData(InputStream is){15 try{16 if(is != null){17 XmlPullParserFactory factory =XmlPullParserFactory.newInstance();18 XmlPullParser parser =factory.newPullParser();19 parser.setInput(is, "UTF-8");20 int eventType =parser.getEventType();21 while(eventType !=XmlPullParser.END_DOCUMENT){22 switch(eventType) {23 caseXmlPullParser.START_DOCUMENT:24 Log.d("xerrard", "START_DOCUMENT=" +parser.getName());25 break;26 caseXmlPullParser.START_TAG:27 String name =parser.getName();28

29 if("current".equals(name)){//current标签

30 Log.d("xerrard", "START_TAG=" +name);31 curCondition = newCurrentWeatherXml();32 }else if(curCondition != null){33 if("city".equals(name)){ //city标签

34 curCondition.city = parser.getAttributeValue(1);35 }36 if("temperature".equals(name)){ //temperature标签

37 curCondition.temperature = parser.getAttributeValue(0);38 }39 if("humidity".equals(name)){ //humidity标签

40 curCondition.humidity = parser.getAttributeValue(0);41 }42 if("direction".equals(name)){ //direction标签

43 curCondition.wind_direction = parser.getAttributeValue(0);44 }45 }46

47

48 break;49

50 caseXmlPullParser.END_TAG:51 if("forecast_conditions".equals(parser.getName())){52 Log.d("xerrard", "END_TAG=" +parser.getName());53 }54 break;55 }56 eventType =parser.next();57 }58 Log.d("xerrard", "curCondition--" +curCondition);59 }60 } catch(Exception e) {61 e.printStackTrace();62 }63 }64

65 }

然后,我们就可以将xml文件作为参数传递给WeatherXmlModel,WeatherXmlModer处理完毕后,得到我们需要的数据CurrentWeatherXml。

1 InputStream inputStream = newFileInputStream(xmlFlie);2 WeatherXMLModel.initData(inputStream);3 CurrentWeatherXml weather =WeatherXMLModel.curCondition;4 TextView hello =(TextView)findViewById(R.id.hello);5 hello.setText(weather.toString());