XML 经常用作 Internet 上的一种数据格式,其文件格式想必大家都比较清楚,在这里我结合Android平台,来说明Android SDK提供的读写XML的package。
首先介绍下Android SDK与Java SDK在读写XML文件方面,数据包之间的关系。Android 平台最大的一个优势在于它利用了 Java 编程语言。Android SDK 并未向标准 Java Runtime Environment (JRE) 提供一切可用功能,但它支持其中很大一部分功能。Java 平台支持通过许多不同的方式来使用 XML,并且大多数与 XML 相关的 Java API 在 Android 上得到了完全支持。举例来说,Java 的 Simple API for XML (SAX) 和 Document Object Model (DOM) 在 Android 上都是可用的,这些 API 多年以来一直都是 Java 技术的一部分,较新的 Streaming API for XML (StAX) 在 Android 中并不可用。但是, Android 提供了一个功能相当的库。最后,Java XML Binding API 在 Android 中也不可用,这个 API 已确定可以在 Android 中实现。Android SDK提供了如下package来支持XML的读写:
包 | 功能介绍 |
javax.xml | 根据 XML 规范定义核心 XML 常量和功能。 |
javax.xml.parsers | 提供DOM和SAX方法解析XML文档 |
org.w3c.dom | W3C提供的使用DOM方法读取XML |
org.xml.sax | 提供核心SAX APIs |
org.xmlpull.v1 |
额外补充说明下,在android.util数据包中也提供了一个类Xml,不过这个类就是把以上package简单封装了下。
读取XML主要有2种方法:DOM与SAX(Simple API for XML),在这里对这2种方法分别加以说明。
DOM(文档对象模型),为XML文档的解析定义了一组接口,解析器读入整个文档,然后构造一个驻留内存的树结构,然后代码就可以使用DOM接口来操组整个树结构,其他点如下:
- 优点:整个文档树都在内存当中,便于操作;支持删除、修改、重新排列等多功能。
- 缺点:将整个文档调入内存(经常包含大量无用的节点),浪费时间和空间。
- 使用场合:一旦解析了文档还需要多次访问这些数据,而且资源比较充足(如内存、CPU等)。
为了解决DOM解析XML引起的这些问题,出现了SAX。SAX解析XML文档为事件驱动,详细说明请阅读Android读写XML(中)–SAX。当解析器发现元素开始、元素结束,文本、文档的开始或者结束时,发送事件,在程序中编写响应这些事件的代码,其特点如下:
- 优点:不用事先调入整个文档,占用资源少。尤其在嵌入式环境中,极力推荐采用SAX进行解析XML文档。
- 缺点:不像DOM一样将文档长期驻留在内存,数据不是持久的,事件过后,如没有保存数据,那么数据就会丢失。
- 使用场合:机器性能有限,尤其是在嵌入式环境,如Android,极力推荐采用SAX进行解析XML文档。
大多数时间,使用 SAX 是比较安全的,并且 Android 提供了一种传统的 SAX 使用方法,以及一个便捷的 SAX 包装器。如果XML文档比较小,那么 DOM 可能是一种比较简单的方法。如果XML文档比较大,但只需要文档的一部分,则 XML Pull 解析器可能是更为有效的方法。最后对于编写 XML,Pull 解析器包也提供了一种便捷的方法,详细说明请阅读Android读写XML(下)——数据写入XML文档。因此,无论我们的 XML 需求如何,Android 都能在一定程度上满足我们的需求。
下面我们详细介绍采用DOM的方法,读取XML文档的思路,这基本上与XML的结构是完全一样的。首先加载XML文档(Document),然后获取文档的根结点(Element),然后获取根结点中所有子节点的列表(NodeList),然后使用再获取子节点列表中的需要读取的结点。根据以上思路,简要写个读取XML文件的例子如下:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import android.content.Context;
void ReadXML()
{
DocumentBuilderFactory docBuilderFactory = null;
DocumentBuilder docBuilder = null;
Document doc = null;
try {
docBuilderFactory = DocumentBuilderFactory.newInstance();
docBuilder = docBuilderFactory.newDocumentBuilder();
//xml file 放到 assets目录中的
doc = docBuilder.parse(context.getResources().getAssets().open(“weather.xml”));
//root element
Element root = doc.getDocumentElement();
//Do something here
//get a NodeList by tagname
NodeList nodeList = root.getElementsByTagName(“tag”);
for(int i =0;i< nodeList.getLength();i++)
{
Node nd = nodeList.item(i);
//Read Node
}
} catch (IOException e) {
} catch (SAXException e) {
} catch (ParserConfigurationException e) {
} finally {
doc = null;
docBuilder = null;
docBuilderFactory = null;
}
}
以上代码比较简单,就不在此详细解析了。
采用DOM读取XML文件,需要加载整个XML文件,在XML文件比较大的情况下,会导致Android设备内存紧张,为了避免这个问题,也可以采用SAX的方法读取XML文件,不过SAX对结点的排序、增加结点等方面的操作相比DOM就有些复杂了。根据XML文件大小、数据处理的需求,选择合适的读取的方法。
对于XML的写入,一方面可以采用前面介绍的这些package;另外一方面也可以按照XML的标准,将数据以字符串的形式直接写入文件,这也是种很不错的方法。在这里推荐IBM开源社区中一篇比较好的文章 Android 上使用 XML,有兴趣的可以去深入学习下。
总结说明
XML作为一种简单的文件格式,作为网络上数据交换的基础,而且得到了大部分数据库的支持(直接将XML文件插入数据库),XML文件的读写只是基础,相信在以后的网络、数据库的开发中会经常使用。
SAX采用基于事件驱动的处理方式,它将XML文档转换成一系列的事件,由单独的事件处理器来决定如何处理。为了了解如何使用SAX API处理XML文档,这里介绍一下SAX所使用的基于事件驱动的处理模式。
基于事件驱动的处理模式
基于事件的处理模式主要围绕着事件源以及事件处理器来工作的。一个可以产生事件的对象被称为事件源,而可以对事件产生响应的对象就被叫做事件处理器。事件源与事件处理对象是通过在事件源中的事件注册方法连接的。当事件源产生事件后,调用事件处理器相应的方法,一个事件获得处理。当在事件源调用事件处理器中特定方法的时候,会传递个事件标志以及其响应事件的状态信息,这样事件处理器才能够根据事件信息来决定自己的行为。
在SAX接口中,事件源是org.xml.sax包中的XMLReader,它通过parser()方法来开始解析XML文档,并根据文档的内容产生事件。而事件处理器则是org.xml.sax包中的ContentHander、DTDHander、ErrorHandler,以及EntityResolver这4个接口,它们分别处理事件源在解析XML文档过程中产生的不同种类的事件。而事件源XMLReader与这4个事件处理器的连接是通过在XMLReader中的相应事件处理器注册方法setXXXX()来完成的,详细介绍请见下表:
以上的4个事件源处理器接口,在开发中没有必要直接从这4个接口直接继承,因为org.xml.sax.helper包为我们提供了类DefaultHandler,其继承了这4个个接口,在实际开发中直接从DefaultHandler继承并实现相关函数就可以了。在这4个接口中,最重要的是ContentHanlder接口,下面就其中的方法加以说明,如下:
以上就是解析一个XML文档,事件处理的过程。这里我们对org.xml.sax.XMLReader中的方法做下补充说明:除了前面介绍的一系列事件处理器注册方法set/getXXXX()外,还有个重要的函数:parse(InputSource input)–Parse an XML document,开始解析一个XML文档。
按照应用程序开发的流程,简要介绍下SAX的使用方法
- 首先,编写了解XML文档的结构,按照XML文档的结构,编写具体的数据结构,类似于:XXXXList,XXXXItem,最好与XML的文档保持一致。
- 其次,开始实现事件处理对象,Android SDK为我们提供了DefaultHandler,其继承了ContentHandler 、DTDHandler、 EntityResolver、 ErrorHandler的所有接口。我们在DefaultHandler的基础上,按照需求实现ContentHanlder的所有接口,这里需要注意2个方面的问题:
- 事件处理的顺序,处理时间的位置:一般在startDocument()初始化工作,在endDocument()中收尾的处理工作;startElement()—characters()—endDocument()是一个XML节点读取的过程,startElement()用来初始判断,characters()获取节点的字符数据,endDocument()将数据写入数据结构。
- 异常SAXException的处理;
- 然后,XML实体解析,过程如下:
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
URL rrl = new URL(urlstring);
InputSource is = new InputSource(url.openStream());
Xmlreader.setContentHanlder(XXXX);
Xmlreader.parse(is); - 最后,在Activity中显示数据,一般先将XML中读取的数据,选择合适的Adaper对数据进行封装,然后使用ListView控件来显示数据。
以上就是SAX读取XML的过程,并显示出最终的数据。以上需要注意的是SAXParserFactory ,SAXParser类来自 javax.xml.parsers包中。
总结说明
SAX读取XML文档的方法,占用内存比较少,但是开发流程相比DOM就复杂多了,具体采用哪种方法比较合适,大家可以在开发的过程中来深刻体会之间的差别。
在前面的2篇文章Android读写XML(上)——package说明、Android读写XML(中)——SAX中想必大家对XML文件读取的方法已经比较熟悉了,在这里我们就不多说了,直接说明如何将信息写成XML文件,首先介绍Andoid SDK中的相关类。
类 | 说明 |
XmlSerializer | Define an interface to serialziation of XML Infoset.定义一个接口来实现XML信息的串行化。 |
什么是串行化?
对象的串型化,也有叫做对象的序列话,并不只是简单的把对象保存在存储器上,它可以使我们在流中传输对象,使对象变的可以像基本数据一样传递。
下面,我们就直接来看个具体的例子来说明,如何使用XmlSerializer。
private String writeXml(){
XmlSerializer serializer = Xml.newSerializer();
StringWriter writer = new StringWriter();
try{
serializer.setOutput(writer);
// <?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?>
serializer.startDocument(“UTF-8″,true);
// <blog number=”1″>
serializer.startTag(“”,”blog”);
serializer.attribute(“”,”number”,String.valueOf(1));
//<message data=”2009-09-23″>
serializer.startTag(“”,”message”);
serializer.attribute(“”,”date”,”2009-09-23″);
// <title>Android XML</title>
serializer.startTag(“”,”title”);
serializer.text(“Android XML”);
serializer.endTag(“”,”title”);
// <url>http://www.moandroid.com/?p=508</url>
serializer.startTag(“”,”url”);
serializer.text(“http://www.moandroid.com/?p=508″);
serializer.endTag(“”,”url”);
//</message>
serializer.endTag(“”,”message”);
// </blog>
serializer.endTag(“”,”blog”);
serializer.endDocument();
return writer.toString();
}
catch(Exception e)
{
throw new RuntimeException(e);
}
}
我们先将writeXml()产生的字符串输出,看是否是按照我们设计的那样,使用Log.v(“XML”, writeXml())输出调试信息。运行程序,在DDMS中查看程序输出的调试信息,如何查看调试信息请阅读Android DDMS如何使用?
输出的字符串如下:
<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?>
<blog number=”1″>
<message data=”2009-09-23″>
<title>Android XML</title>
<url>http://www.moandroid.com/?p=508</url>
</message>
</blog>
看了运行的结果,对于上面代码的功能,估计大家就明白了,不再这里详细解析。
下面,进一步将字符串写入文件,代码如下:
public boolean Write(String path,String txt)
{
try
{
OutputStream os = openFileOutput(path,MODE_PRIVATE);
OutputStreamWriter osw=new OutputStreamWriter(os);
osw.write(txt);
osw.close();
os.close();
}
catch(FileNotFoundException e)
{
return false;
}
catch(IOException e)
{
return false;
}
return true;
}
}
在onCreate()中增加如下代码:Write(“blog.xml”,writeXml())。运行程序,打开DDMS查看写入的XML文档,文件存放在data/data/{package}/files文件夹下,如下:
还可以将这个文件从File Explorer中导出到电脑中查看XML文档的具体内容,与输出的字符串完全一样。
总结说明
XML文件的写入就完成了,想必大家对串行化也有应该有一些了解,具体的需要引用那些package请大家到Android SDK去仔细查看吧。