android解析xml文件的方式

更新时间:2023-09-19 16:02:01 阅读量: 小学教育 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

android解析xml文件的方式(其一)

在androd手机中处理xml数据时很常见的事情,通常在不同平台传输数据的时候,我们就可能使用xml,xml是与平台无关的特性,被广泛运用于数据通信中,那么在android中如何解析xml文件数据呢? 通常有三种方式:DOM,SAX,PULL 在这一节中我们使用DOM方式来处理。

DOM方式解析xml是先把xml文档都读到内存中,然后再用DOM API来访问树形结构,并获取数据的,但是这样一来,如果xml文件很大呢?手机CPU处理能力当然不能与PC机器比,因此在处理效率方面就相对差了,当然这是对于其他方式处理xml文档而言。

解析xml文档,当然必须有xml文档文件啦,我自己胡乱弄了一个river,放在assets目录.如下:

View Code

灵渠在广西壮族自治区兴安县境内,是世界上最古老的运河之一,有着“世界古代水利建筑明珠”的美誉。灵渠古称秦凿渠、零渠、陡河、兴安运河,于公元前214年凿成通航,距今已2217年,仍然发挥着功用。

http://imgsrc.http://www.wodefanwen.com//baike/pic/item/389aa8fdb7b8322e08244d3c.jpg

胶莱运河南起黄海灵山海口,北抵渤海三山岛,流经现胶南、胶州、平度、高密、昌邑和莱州等,全长200公里,流域面积达5400平方公里,南北贯穿山东半岛,沟通黄渤两海。胶莱运河自平度姚家村东的分水岭南北分流。南流由麻湾口入胶州湾,为南胶莱河,长30公里。北流由海仓口入莱州湾,为北胶莱河,长100余公里。

http://imgsrc.http://www.wodefanwen.com//baike/pic/item/389aa8fdb7b8322e08244d3c.jpg

位于淮河下游江苏省北部,西起洪泽湖边的高良涧,流经洪泽,青浦、淮安,阜宁、射阳,滨海等六县(区),东至扁担港口入海的大型人工河道。全长168km。

http://imgsrc.http://www.wodefanwen.com//baike/pic/item/389aa8fdb7b8322e08244d3c.jpg 那么如何处理呢? 具体思路是:

*首先利用DocumentBuilderFactory创建一个DocumentBuilderFactory实例 *然后利用DocumentBuilderFactory创建DocumentBuilder *然后加载XML文档(Document), * 然后获取文档的根结点(Element),

* 然后获取根结点中所有子节点的列表(NodeList), * 然后使用再获取子节点列表中的需要读取的结点。

当然我们观察节点,我需要用一个River对象来保存数据,抽象出River类 View Code

public class River implements Serializable {

private static final long serialVersionUID = 1L; private String name;

public String getName() { return name; }

public void setName(String name) { this.name = name; }

public int getLength() { return length; }

public void setLength(int length) { this.length = length;

}

public String getIntroduction() { return introduction; }

public void setIntroduction(String introduction) { this.introduction = introduction; }

public String getImageurl() { return imageurl; }

public void setImageurl(String imageurl) { this.imageurl = imageurl; }

private int length;

private String introduction; private String imageurl; }

下面我们就开始读取xml文档对象,并添加进List中:代码如下:

我们这里是使用assets中的river.xml文件,那么就需要读取这个xml文件,返回输入流。

读取方法为:

inputStream=this.context.getResources().getAssets().open(fileName); 参数是xml文件路径,当然默认的是assets目录为根目录。

然后可以用DocumentBuilder对象的parse方法解析输入流,并返回document对象,然后再遍历doument对象的节点属性。

View Code

//获取全部河流数据 /**

* 参数fileName:为xml文档路径 */

public List getRiversFromXml(String fileName){ List rivers=new ArrayList(); DocumentBuilderFactory factory=null; DocumentBuilder builder=null; Document document=null;

InputStream inputStream=null; //首先找到xml文件

factory=DocumentBuilderFactory.newInstance(); try {

//找到xml,并加载文档

builder=factory.newDocumentBuilder();

inputStream=this.context.getResources().getAssets().open(fileName); document=builder.parse(inputStream); //找到根Element

Element root=document.getDocumentElement();

NodeList nodes=root.getElementsByTagName(RIVER); //遍历根节点所有子节点,rivers 下所有river River river=null;

for(int i=0;i

Element riverElement=(Element)(nodes.item(i)); //获取river中name属性值

river.setName(riverElement.getAttribute(NAME));

river.setLength(Integer.parseInt(riverElement.getAttribute(LENGTH))); //获取river下introduction标签 Element

introduction=(Element)riverElement.getElementsByTagName(INTRODUCTION).item(0);

river.setIntroduction(introduction.getFirstChild().getNodeValue()); Element

imageUrl=(Element)riverElement.getElementsByTagName(IMAGEURL).item(0);

river.setImageurl(imageUrl.getFirstChild().getNodeValue()); rivers.add(river); }

}catch (IOException e){ e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); }

catch (ParserConfigurationException e) { e.printStackTrace(); }finally{ try {

inputStream.close();

} catch (IOException e) { e.printStackTrace(); } }

return rivers; }

在这里添加到List中, 然后我们使用ListView将他们显示出来。如图所示:

android解析xml文件的方式(其二)

上一节中,我们使用DOM方式解析xml文档,该方式比较符合我们日常思维方式,容易上手,但是它直接把文档调入内存中,比较耗内存。在这里我们可以用另外一种方式解析xml,这个就是SAX方式。 SAX即是:Simple API for XML

SAX是基于事件驱动的。当然android的事件机制是基于回调函数的,在用SAX解析xml文档时候,在读取到文档开始和结束标签时候就会回调一个事件,在读取到其他节点与内容时候也会回调一个事件。

既然涉及到事件,就有事件源,事件处理器。在SAX接口中,事件源是org.xml.sax包中的XMLReader,它通过parser()方法 来解析XML文档,并产生事件。事件

处理器是org.xml.sax包中ContentHander、DTDHander、ErrorHandler,以 及EntityResolver这4个接口

XMLReader通过相应事件处理器注册方法setXXXX()来完成的与ContentHander、DTDHander、ErrorHandler,以及EntityResolver这4个接口的连接,详细介绍请见下表:

但是我们无需都继承这4个接口,SDK为我们提供了DefaultHandler类来处理,DefaultHandler类的一些主要事件回调方法如下:

由以上可知,我们需要XmlReader 以及DefaultHandler来配合解析xml。 处理思路是:

1:创建SAXParserFactory对象

2: 根据SAXParserFactory.newSAXParser()方法返回一个SAXParser解析器 3:根据SAXParser解析器获取事件源对象XMLReader 4:实例化一个DefaultHandler对象

5:连接事件源对象XMLReader到事件处理类DefaultHandler中 6:调用XMLReader的parse方法从输入源中获取到的xml数据 7:通过DefaultHandler返回我们需要的数据集合。 代码如下:

View Code

public List parse(String xmlPath){ List rivers=null;

SAXParserFactory factory=SAXParserFactory.newInstance(); try {

SAXParser parser=factory.newSAXParser();

//获取事件源

XMLReader xmlReader=parser.getXMLReader(); //设置处理器

RiverHandler handler=new RiverHandler(); xmlReader.setContentHandler(handler); //解析xml文档

//xmlReader.parse(new InputSource(new URL(xmlPath).openStream())); xmlReader.parse(new

InputSource(this.context.getAssets().open(xmlPath))); rivers=handler.getRivers();

} catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SAXException e) {

// TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }

return rivers; }

重点在于DefaultHandler对象中对每一个元素节点,属性,文本内容,文档内容进行处理。

前面说过DefaultHandler是基于事件处理模型的,基本处理方式是:当SAX解析器导航到文档开始标签时回调 startDocument方法,导航到文档结束标签时回调endDocument方法。当SAX解析器导航到元素开始标签时回调

startElement方法,导航到其文本内容时回调characters方法,导航到标签结束时回调endElement方法。

根据以上的解释,我们可以得出以下处理xml文档逻辑:

1:当导航到文档开始标签时,在回调函数startDocument中,可以不做处理,当然你可以验证下UTF-8等等。

2:当导航到rivers开始标签时,在回调方法startElement中可以实例化一个集合用来存贮list,不过我们这里不用,因为在构造函数中已经实例化了。 3:导航到river开始标签时,就说明需要实例化River对象了,当然river标签中还有name ,length属性,因此实例化River后还必须取出属性值,

attributes.getValue(NAME),同时赋予river对象中,同时添 加为导航到的river标签添加一个boolean为真的标识,用来说明导航到了river元素。

4:当然有river标签内还有子标签(节点),但是SAX解析器是不知道导航到什么标签的,它只懂得开始,结束而已。那么如何让它认得我们的各个 标签呢?当然需要判断了,于是可以使用回调方法startElement中的参数String

localName,把我们的标签字符串与这个参数比较下,就可以了。我们还必须让SAX知道,现在导航到的是某个标签,因此添加一个true属性让 SAX解析器知道。因此

5:它还会导航到文本内标签,(就是里面的内容),回调方法characters,我们一般在这个方法中取出就是里面的内容,并保存。 6:当然它是一定会导航到结束标签 或者的,如果是标签,记得把river对象添加进list中。如果是river中的子标 签

,就把前面设置标记导航到这个标签的boolean标记设置为false.

按照以上实现思路,可以实现如下代码:

View Code

/**导航到开始标签触发**/

public void startElement (String uri, String localName, String qName, Attributes attributes){

String tagName=localName.length()!=0?localName:qName; tagName=tagName.toLowerCase().trim();

//如果读取的是river标签开始,则实例化River if(tagName.equals(RIVER)){ isRiver=true;

river=new River();

/**导航到river开始节点后**/

river.setName(attributes.getValue(NAME));

river.setLength(Integer.parseInt(attributes.getValue(LENGTH))); }

//然后读取其他节点 if(isRiver){

if(tagName.equals(INTRODUCTION)){ xintroduction=true;

}else if(tagName.equals(IMAGEURL)){ ximageurl=true; } } }

/**导航到结束标签触发**/

public void endElement (String uri, String localName, String qName){

String tagName=localName.length()!=0?localName:qName; tagName=tagName.toLowerCase().trim();

//如果读取的是river标签结束,则把River添加进集合中 if(tagName.equals(RIVER)){ isRiver=true;

rivers.add(river); }

//然后读取其他节点 if(isRiver){

if(tagName.equals(INTRODUCTION)){ xintroduction=false;

}else if(tagName.equals(IMAGEURL)){ ximageurl=false; } } }

//这里是读取到节点内容时候回调

public void characters (char[] ch, int start, int length){ //设置属性值

if(xintroduction){ //解决null问题

river.setIntroduction(river.getIntroduction()==null?\duction()+new String(ch,start,length)); }else if(ximageurl){ //解决null问题

river.setImageurl(river.getImageurl()==null?\new String(ch,start,length)); } } 运行结果如下:

[环境]:SAX 2.0 ,Xerces-J 2.9.1

1、SAX2.0使用org.xml.sax.XMLReader接口代替了Parser接口。如果要使用SAX解析XML,那么首先要获得XMLReader的一个实现对象。

(1)、使用javax.xml.parsers.SAXParser创建XMLReader

Sun JDK提供了javax.xml.parsers.SAXParser,由SAXParser可以获取一个XMLReader。由于 javax.xml.parsers.SAXParser是JDK自带驱动,所以,直接编译就可以运行了。

SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setValidating(true);//开启验证XML功能

SAXParser parser = factory.newSAXParser(); XMLReader reader = parser.getXMLReader();

(2)、使用第三方驱动。本例使用Xerces驱动: org.apache.xerces.parsers.SAXParser。

Xerces驱动下载地址:http://xerces.apache.org/xerces2-j/。 下载后,找到xercesImpl.jar,并将其加入到classpath路径中。如果不加入classpath路径,可以在编译运行时指定xercesImpl.jar的位置。例: javac -cp \java -cp \ 此时,创建XMLReader代码如下:

XMLReader reader = XMLReaderFactory.createXMLReader(); 但是运行时要指定驱动的位置:

java -Dorg.xml.sax.driver=org.apache.xerces.parsers.SAXParser SAXDemo 也可以在代码中指定具体驱动:

String driver = \

XMLReader reader = XMLReaderFactory.createXMLReader(driver); 或者直接创建一个XMLReader:

XMLReader reader = new org.apache.xerces.parsers.SAXParser(); 2、得到XMLReader对象之后就可以解析XML了。SAX是基于事件的,所以,还要设置内容事件处理器ContentHandler和其它事件处理 器,

DefaultHandler是对ContentHandler等事件处理接口的一个默认实现,如果熟悉AWT/Swing事件处理机制,便不难理 解。当然还需要一个InputSource来指定所要解析的XML文件。

reader.setFeature(\reader.setContentHandler(mySAXHandler); reader.setErrorHandler(mySAXHandler);

reader.parse(input);//input是InputSouce类型

3、SAX解析XML完整的代码实现(注释中包含使用Xerces驱动的方法,可根据需要删除或选用):

/**

* SAX使用示例 *

*Usage:

*如果未用到Xerces驱动,则直接编译运行。 *如果用Xerces驱动,则编译运行如下:

* javac -cp \ * java -cp \ *

* @version 2009-4-25

* @author Winty(wintys@gmail.com) */

import java.io.*;

import javax.xml.parsers.SAXParserFactory; import javax.xml.parsers.SAXParser;

import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.XMLReader; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.Attributes;

import org.xml.sax.SAXParseException;

import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory;

public class SAXDemo extends DefaultHandler{ Writer writer;

InputSource input;

public SAXDemo(InputSource input , Writer writer){ this.input = input; this.writer = writer; }

public static void main(String[] args)throws Exception{ InputSource input; Writer writer; SAXDemo saxDemo;

input = new InputSource(new FileReader(\ writer = new OutputStreamWriter(System.out); //writer = new FileWriter(\

saxDemo= new SAXDemo(input , writer);

saxDemo.parse(); }

public void parse(){

XMLReader reader; try{

reader = getXMLReader_Java();

/*方法2: 使用Xerces驱

动:org.apache.xerces.parsers.SAXParser,

需指定:java -cp \ */

//如果使用Xerces驱动,则去除相应方法的注释即可。 //reader = getXMLReader_Xerces1(); //reader = getXMLReader_Xerces2(); //reader = getXMLReader_Xerces3();

MySAXHandler mySAXHandler = new MySAXHandler(writer);

reader.setFeature(\ reader.setContentHandler(mySAXHandler); reader.setErrorHandler(mySAXHandler);

reader.parse(input); }catch(SAXException e){

System.err.println(e.getMessage()); }catch(IOException e){

System.err.println(e.getMessage()); } }

//方法1:使用javax.xml.parsers.SAXParser驱动

private XMLReader getXMLReader_Java()throws SAXException { XMLReader reader = null; try{

SAXParserFactory factory = SAXParserFactory.newInstance();

factory.setValidating(true);

SAXParser parser = factory.newSAXParser(); reader = parser.getXMLReader();

}catch(ParserConfigurationException e){

System.err.println(e.getMessage()); }

return reader; }

/**

*方法2-1: */

/*private XMLReader getXMLReader_Xerces1()throws SAXException{ String driver = \

return XMLReaderFactory.createXMLReader(driver); }*/

/* 方法2-2:

* 还需指定driver类: java

-Dorg.xml.sax.driver=org.apache.xerces.parsers.SAXParser */

/*private XMLReader getXMLReader_Xerces2()throws SAXException{ return XMLReaderFactory.createXMLReader(); }*/

/**

* 方法2-3:

* 还需指定:javac -cp \ */

/*private XMLReader getXMLReader_Xerces3()throws SAXException{ return (new org.apache.xerces.parsers.SAXParser()); }*/ }

class MySAXHandler extends DefaultHandler{ private Writer writer;

public MySAXHandler(Writer writer){ this.writer = writer; }

public void startDocument()throws SAXException{ try{

writer.write(\开始解析XMLn\ }catch(IOException e){

* @param start * @param length

* @throws SAXException */

public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { }

/**

* 在解析到处理指令时,调用此方法。

* 这些处理指令不包括XML的版权指令,它由解析器本身识别。 * @param target * @param data

* @throws SAXException */

public void processingInstruction(String target, String data) throws SAXException { }

/**

* 当未验证解析器忽略实体时调用此方法 * @param name

* @throws SAXException */

public void skippedEntity(String name) throws SAXException { } }

---------- MyErrorHandler.java ----------

import org.xml.sax.SAXException;

import org.xml.sax.SAXParseException; import org.xml.sax.ErrorHandler;

public class MyErrorHandler implements ErrorHandler {

public MyErrorHandler() {

}

/**

* XML的警告信息 * @param exception

* @throws SAXException */

public void warning(SAXParseException exception) throws SAXException {

System.out.println(\

System.out.println(exception.getLineNumber() + \etSystemId() + \ }

/**

* 不符合XML规范时调用此方法 * @param exception

* @throws SAXException */

public void error(SAXParseException exception) throws SAXException {

System.out.println(\

System.out.println(exception.getLineNumber() + \etSystemId() + \ }

/**

* 非良构的文档时调用此方法 * @param exception

* @throws SAXException */

public void fatalError(SAXParseException exception) throws SAXException {

System.out.println(\

System.out.println(exception.getLineNumber() + \etSystemId() + \ } }

---------- MyDTDHandler.java ----------

import org.xml.sax.SAXException;

import org.xml.sax.DTDHandler;

public class MyDTDHandler implements DTDHandler {

public MyDTDHandler() { }

/**

* 当实体声明为不必解析的实体时调用此方法,比如NDATA类型。 * @param name

* @param publicId * @param systemId

* @throws SAXException */

public void notationDecl(String name, String publicId, String systemId) throws SAXException {

System.out.println(\ System.out.println(\

System.out.println(\ System.out.println(\ }

/**

* 当处理符号声明时调用此方法,比如NOTATION。 * @param name

* @param publicId * @param systemId

* @param notationName * @throws SAXException */

public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException {

System.out.println(\ System.out.println(\

System.out.println(\ System.out.println(\

System.out.println(\ } }

---------- 解析后得到结果 ----------

**** Student information start **** name:bigmouse sex:male math:60 Englist:59 autoCAD:80 SCM:90

mechanics:61

------------------------------------ name:coco sex:female math:90 Englist:95 C++:80 Java:85

------------------------------------ **** Student information end ****

四.关于其他技术

上 面介绍了SAX解析XML文档的方法,它不将整个文档放入内存,而是以基于事件的方式来处理文档,因此在速度和性能上优于DOM。但是在可读性上,SAX 却不如DOM操作清楚简单。因此在文档不是特别大的时候,还是采用DOM方法比较合适。另外还有一种解析XML的API -- JDOM,它是一种基于 Java2的完整API,同样具有SAX的高效,快速的特点,而且还可以像DOM那样从整体上操纵文档,提供一种比DOM更简单的生成和访问元素节点的方 法。我将会在以后的文章中介绍DOM,JDOM以及JAXP等技术。

本文来源:https://www.bwwdw.com/article/ysph.html

Top