1、第15章 Android XML解析,Android实现XML解析技术XML在各种开发中都广泛应用,Android也不例外。作为承载数据的一个重要角色,如何读写XML成为Android开发中一项重要的技能。在Android中,常见的XML解析器分别为DOM解析器、SAX解析器和PULL解析器。 1 第一种方式:DOM解析器: DOM是基于树形结构的的节点或信息片段的集合,允许开发人员使用DOM API遍历XML树、检索所需数据。分析该结构通常需要加载整个文档和构造树形结构,然后才可以检索和更新节点,信息。Android完全支持DOM 解析。利用DOM中的对象,可以对XML文档进行读取、搜索、修
2、改、添加和删除等操作。DOM的工作原理:使用DOM对XML文件进行操作时,首先要解析文件,将文件分为独立的元素、属性和注释等,然后以节点树的形式在内存中对XML文件进行表示,就可以通过节点树访问文档的内容,并根据需要修改文档这就是DOM的工作原理。DOM实现时首先为XML文档的解析定义一组接口,解析器读入整个文档,然后构造一个驻留内存的树结构,这样代码就可以使用DOM接口来操作整个树结构。由于DOM在内存中以树形结构存放,因此检索和更新效率会更高。但是对于特别大的文档,解析和加载整个文档将会很耗资源。 当然,如果XML文件的内容比较小,采用DOM是可行的。,常用的DoM接口和类:Documen
3、t:该接口定义分析并创建DOM文档的一系列方法,它是文档树的根,是操作DOM的基础。 Element:该接口继承Node接口,提供了获取、修改XML元素名字和属性的方法。Node:该接口提供处理并获取节点和子节点值的方法。NodeList:提供获得节点个数和当前节点的方法。这样就可以迭代地访问各个节点。DOMParser:该类是Apache的Xerces中的DOM解析器类,可直接解析XML文件。,DOM解析XML,public class XMLActivity extends Activity private static final String TAG = “XMLActivity“;O
4、verride public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView textView = (TextView) this.findViewById(R.id.show); InputStream inputStream = this.getClass().getClassLoader() .getResourceAsStream(“person.xml“); DOMPersonService saxP
5、ersonService = new DOMPersonService(); try /List persons = saxPersonService.getSAXPersons(inputStream); List persons = saxPersonService.getDOMPersons(inputStream);inputStream.close(); StringBuffer sb = new StringBuffer(); for (Person person : persons) sb.append(person.toString().append(“n“); textVie
6、w.setText(sb.toString(); catch (IOException e) Log.i(TAG, e.getMessage(); e.printStackTrace(); catch (Exception e) Log.i(TAG, e.getMessage(); e.printStackTrace();,public class DOMPersonService public static List getDOMPersons(InputStream inStream) throws ExceptionList persons = new ArrayList();Docum
7、entBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = factory.newDocumentBuilder();Document document = builder.parse(inStream);Element root = document.getDocumentElement();NodeList personNodes = root.getElementsByTagName(“person“);/查找所有person节点for(int i = 0 ; i p
8、ersonNodes.getLength() ; i+)Person person = new Person(); Element personNode = (Element)personNodes.item(i);/获取person节点的id属性值int id = new Integer(personNode.getAttribute(“id“);person.setId(id);/获取person节点下的所有子节点(标签之间的空白节点和name/age元素)NodeList childNodes = personNode.getChildNodes();for(int y = 0 ; y
9、childNodes.getLength() ; y+)Node childNode = childNodes.item(y); if(childNode.getNodeType()=Node.ELEMENT_NODE) if(“name“.equals(childNode.getNodeName()String name = childNode.getFirstChild().getNodeValue();person.setName(name); else if(“age“.equals(childNode.getNodeName()String age = childNode.getFi
10、rstChild().getNodeValue();person.setAge(new Short(age); , persons.add(person); return persons; ,2 第二种方式:SAX解析器:SAX(Simple API for XML)解析器是一种基于事件的解析器,事件驱动的流式解析方式是,从文件的开始顺序解析到文档的结束,不可暂停或倒退。它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的。当事件源产生事件后,调用事件处理器相应的处理方法,一个事件就可以得到处理。在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事
11、件处理器才能够根据提供的事件信息来决定自己的行为。,SAX解析器的优点是解析速度快,占用内存少。非常适合在Android移动设备中使用。 SAX的工作原理:SAX的工作原理简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。在SAX接口中,事件源是org.xml.sax包中的XMLReader,它通过parser()方法来解析XML文档,并产生事件。事件处理器是org.xml.sax包中ContentHander、DTDHa
12、nder、ErrorHandler,以及EntityResolver这4个接口。XMLReader通过相应事件处理器注册方法setXXXX()来完成的与ContentHander、DTDHander、ErrorHandler,以及EntityResolver这4个接口的连接。,常用的SAX接口和类: Attrbutes:用于得到属性的个数、名字和值。 ContentHandler:定义与文档本身关联的事件(例如,开始和结束标记)。大多数应用程序都注册这些事件。DTDHandler:定义与DTD关联的事件。它没有定义足够的事件来完整地报告DTD。如果需要对DTD进行语法分析,请使用可选的Decl
13、Handler。DeclHandler是SAX的扩展。不是所有的语法分析器都支持它。EntityResolver:定义与装入实体关联的事件。只有少数几个应用程序注册这些事件。ErrorHandler:定义错误事件。许多应用程序注册这些事件以便用它们自己的方式报错。DefaultHandler:它提供了这些接LI的缺省实现。在大多数情况下,为应用程序扩展DefaultHandler并覆盖相关的方法要比直接实现一个接口更容易。,可知,我们需要XmlReader 以及DefaultHandler来配合解析xml。,SAX解析XML,public class XMLActivity extends A
14、ctivity private static final String TAG = “XMLActivity“;Override public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView textView = (TextView) this.findViewById(R.id.show); InputStream inputStream = this.getClass().getClassLoader()
15、.getResourceAsStream(“person.xml“); SAXPersonService saxPersonService = new SAXPersonService(); try /List persons = saxPersonService.getSAXPersons(inputStream); List persons = saxPersonService.getSAXPersons(inputStream);inputStream.close(); StringBuffer sb = new StringBuffer(); for (Person person :
16、persons) sb.append(person.toString().append(“n“); textView.setText(sb.toString(); catch (IOException e) Log.i(TAG, e.getMessage(); e.printStackTrace(); catch (Exception e) Log.i(TAG, e.getMessage(); e.printStackTrace();,public class SAXPersonService public List getSAXPersons(InputStream inStream) th
17、rows Exception SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser();/创建解析器 /设置解析器的相关特性,http:/xml.org/sax/features/namespaces = true 表示开启命名空间特性,这个可以不写 /saxParser.setProperty(“http:/xml.org/sax/features/namespaces“,true); PersonHandler handler = new Pers
18、onHandler(); parser.parse(inStream, handler); inStream.close(); return handler.getPersons(); private final class PersonHandler extends DefaultHandler private List persons = null; private Person person = null; private String tag = null;/当前解析的元素标签public List getPersons() return persons; Override publi
19、c void startDocument() throws SAXException persons = new ArrayList();/* 接收元素开始的通知。* namespaceURI:元素的命名空间* localName:元素的本地名称(不带前缀)* qName:元素的限定名(带前缀)* atts:元素的属性集合*/,Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException if(“person“.eq
20、uals(localName) person = new Person(); person.setId(new Integer(attributes.getValue(0); tag = localName; Override public void characters(char ch, int start, int length) throws SAXException if(tag!=null) String textdata = new String(ch, start, length); if(“name“.equals(tag) person.setName(textdata);
21、else if(“age“.equals(tag) person.setAge(new Short(textdata); Override public void endElement(String uri, String localName, String qName) throws SAXException if(“person“.equals(localName) persons.add(person); person = null; tag = null; ,3 第三种方式:PULL解析器:Android并未提供对Java StAX API的支持。但是,Android附带了一个pull
22、解析器,其工作方式类似于StAX。它允许用户的应用程序代码从解析器中获取事件,这与SAX解析器自动将事件推入处理程序相反。PULL解析器的运行方式和SAX类似,都是基于事件的模式。不同的是,在PULL解析过程中返回的是数字,且我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。读取到xml的声明返回 START_DOCUMENT; 读取到xml的结束返回 END_DOCUMENT ; 读取到xml的开始标签返回 START_TAG 读取到xml的结束标签返回 END_TAG 读取到xml的文本返回 TEXT PULL解析器小巧轻便,解析速度快
23、,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器,Android官方推荐开发者们使用Pull解析技术。Pull解析技术是第三方开发的开源技术,它同样可以应用于JavaSE开发。,PULL 的工作原理:XML pull提供了开始元素和结束元素。当某个元素开始时,我们可以调用parsernextText从XML文档中提取所有字符数据。当解释到一个文档结束时,自动生成EndDocument事件。常用的XML pull的接口和类:XmlPullParser:XML pull解析器是一个在XMLPULL VlAP1中提供了定义解析功能的接口
24、。XmlSerializer:它是一个接口,定义了XML信息集的序列。XmlPullParserFactory:这个类用于在XMPULL V1 API中创建XML Pull解析器。XmlPullParserException:抛出单一的XML pull解析器相关的错误。,PULL的解析流程如下,Android中内置的Pull解析器,因此可以使用Pull解析器解析XML文件。 Pull解析器的运行方式与 SAX 解析器相似。它提供了类似的事件,如:开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。事件将作为数值代码被发送,因此可以使用一个switch对感兴趣
25、的事件进行处理。当元素开始解析时,调用parser.nextText()方法可以获取下一个Text类型元素的值。,Pull解析XML,public class XMLActivity extends Activity private static final String TAG = “XMLActivity“;Override public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView textView =
26、 (TextView) this.findViewById(R.id.show); InputStream inputStream = this.getClass().getClassLoader() .getResourceAsStream(“person.xml“); PullPersonService saxPersonService = new PullPersonService(); try /List persons = saxPersonService.getSAXPersons(inputStream); List persons = saxPersonService.getP
27、ersons(inputStream);inputStream.close(); StringBuffer sb = new StringBuffer(); for (Person person : persons) sb.append(person.toString().append(“n“); textView.setText(sb.toString(); catch (IOException e) Log.i(TAG, e.getMessage(); e.printStackTrace(); catch (Exception e) Log.i(TAG, e.getMessage(); e
28、.printStackTrace();,public class PullPersonService public static List getPersons(InputStream inStream) throws Exception List persons = null; Person person = null; / xmlPullParserFactory=XmlPullParserFactory.newInstance(); / XmlPullParser pullParser =xmlPullParserFactory.newPullParser(); XmlPullParse
29、r pullParser = Xml.newPullParser();/ 这行代码同上面两行 / 解析XML pullParser.setInput(inStream, “UTF-8“); int event = pullParser.getEventType(); while (event != XmlPullParser.END_DOCUMENT) switch (event) / 文档开始 case XmlPullParser.START_DOCUMENT: persons = new ArrayList(); break; / 节点开始 case XmlPullParser.START
30、_TAG: if (“person“.equals(pullParser.getName() int id = new Integer(pullParser.getAttributeValue(0); person = new Person(); person.setId(id); if (person != null) if (“name“.equals(pullParser.getName() String name = pullParser.nextText();/ 如果后面是Text元素,即返回它的值 person.setName(name); else if (“age“.equal
31、s(pullParser.getName() ,String age = pullParser.nextText(); person.setAge(new Short(age); break; / 节点结束 case XmlPullParser.END_TAG: if (“person“.equals(pullParser.getName() persons.add(person); person = null; break; event = pullParser.next(); return persons; public static void save(List persons, Out
32、putStream outStream) throws ExceptionXmlSerializer serializer = Xml.newSerializer();serializer.setOutput(outStream, “UTF-8“);serializer.startDocument(“UTF-8“, true);serializer.startTag(null, “persons“);/ serializer.startTag(“, “persons“);for(Person person : persons)serializer.startTag(null, “person“
33、);/ serializer.startTag(“, “person“);serializer.attribute(null, “id“, person.getId().toString(); / serializer.attribute(“, “id“, person.getId().toString();serializer.startTag(null, “name“); /serializer.startTag(“, “name“);serializer.text(person.getName();serializer.endTag(null, “name“);/ serializer.
34、endTag(“, “name“);serializer.startTag(null, “age“); /serializer.startTag(“, “age“);serializer.text(person.getAge().toString();,serializer.endTag(null, “age“); / serializer.endTag(“, “age“);serializer.endTag(null, “person“);/serializer.endTag(“, “person“); serializer.endTag(null, “persons“); /seriali
35、zer.endTag(“, “persons“); serializer.endDocument();outStream.flush();outStream.close(); public static void save(List persons,Writer write) throws ExceptionXmlSerializer serializer = Xml.newSerializer();serializer.setOutput(write);serializer.startDocument(“UTF-8“, true);serializer.startTag(null, “per
36、sons“);/ serializer.startTag(“, “persons“);for(Person person : persons)serializer.startTag(null, “person“);/ serializer.startTag(“, “person“);serializer.attribute(null, “id“, person.getId().toString(); / serializer.attribute(“, “id“, person.getId().toString();serializer.startTag(null, “name“); /seri
37、alizer.startTag(“, “name“);serializer.text(person.getName();serializer.endTag(null, “name“);/ serializer.endTag(“, “name“);serializer.startTag(null, “age“); /serializer.startTag(“, “age“);serializer.text(person.getAge().toString();serializer.endTag(null, “age“); / serializer.endTag(“, “age“);serializer.endTag(null, “person“);/serializer.endTag(“, “person“); serializer.endTag(null, “persons“); /serializer.endTag(“, “persons“); serializer.endDocument();write.flush();write.close();,