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
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 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等技术。
- 通信原理实验报告
- 2016年上半年安徽省临床医学检验技术中级技师职称试题
- 传智播客刘意老师JAVA全面学习笔记
- 星级酒店客房部保洁服务标准与工作流程操作规范 - PA新员
- 算法竞赛入门经典授课教案第1章 算法概述
- 《微信公众平台架起家校互通桥》结题报告
- 2018年宁夏银川市高考数学三模试卷(理)Word版含解析
- 大学生创业基础 - 尔雅
- 2016年6月英语六级真题写作范文3套
- 中国磁性材料纸行业专项调查与发展策略分析报告(2015-2020)
- 云南省2018届高三普通高中学业水平考试化学仿真试卷二Word版缺答案
- 窗函数法设计低通滤波器
- 第三章 绩效考评方法与绩效管理模式
- 高等数学教案
- 个人独资合伙企业习题及答案
- 小学语文沪教版三年级上册第六单元第30课《想别人没想到的》公开课优质课教案比赛讲课获奖教案
- 曳引钢丝绳及其他曳引系统校核计算 - 图文
- 淮阴工学院管理学期末试卷7 - 图文
- 受力分析方法(1)
- 2013-2014学年陕西省西安市西工大附小五年级(上)期末数学试卷及解析
- 解析
- android
- 方式
- 文件
- xml