本文共 14453 字,大约阅读时间需要 48 分钟。
<p>今日继续学习Android中使用Pull的XML解析技术实现对XML文件的解析和创建。由于明天休息,时间比较充裕,所以我也将昨天未总结的SAX解析技术在此做个总结。 </p> <p><strong>一、SAX解析技术</strong></p> <p>Sax使用的是事件驱动的流式解析技术。事件驱动的流式解析方式是,从文件的开始顺序解析到文档的结束,不可暂停或倒退。当解析到文档的开始或结束、元素的开始或结束等都会触发一个事件,我们在事件处理方法中完成对数据的操作。由此可见,我们需要编写实现了事件接口的类。</p> <p><strong>1.</strong><strong>创建Android工程(eclipse3.5):</strong></p> <p>Project name:AndroidXML</p> <p>BuildTarget:Android2.1</p> <p>Application name:Android XML 解析技术</p> <p>Package name:com.changcheng.androidxml</p> <p>Create Activity:AndroidXML</p> <p>Min SDK Version:7</p> <p><strong>2.</strong><strong>需要解析的XML文件:</strong></p> <p><!--l version=<-->"1.0" encoding=<em>"UTF-8"</em>?></p> <p></p> <p>"23"></p> <p>C++ Primer 4</p> <p>78</p> <p></p> <p>"20"></p> <p>Think in Java</p> <p>76</p> <p></p> <p></p> <p><strong></strong>该文件存放于src源码目录。</p> <p><strong>3.XML</strong><strong>文件对应的实体Book:</strong></p> <p><strong>package</strong> com.changcheng.androidxml.entity;</p> <p><strong>public</strong> <strong>class</strong> Book {</p> <p><strong>private</strong> <strong>int</strong> id;</p> <p><strong>private</strong> String name;</p> <p><strong>private</strong> <strong>float</strong> price;</p> <p><strong>public</strong> Book() {</p> <p>}</p> <p><strong>public</strong> Book(<strong>int</strong> id, String name, <strong>float</strong> price) {</p> <p><strong>this</strong>.id = id;</p> <p><strong>this</strong>.name = name;</p> <p><strong>this</strong>.price = price;</p> <p>}</p> <p><strong>public</strong> <strong>int</strong> getId() {</p> <p><strong>return</strong> id;</p> <p>}</p> <p><strong>public</strong> <strong>void</strong> setId(<strong>int</strong> id) {</p> <p><strong>this</strong>.id = id;</p> <p>}</p> <p><strong>public</strong> String getName() {</p> <p><strong>return</strong> name;</p> <p>}</p> <p><strong>public</strong> <strong>void</strong> setName(String name) {</p> <p><strong>this</strong>.name = name;</p> <p>}</p> <p><strong>public</strong> <strong>float</strong> getPrice() {</p> <p><strong>return</strong> price;</p> <p>}</p> <p><strong>public</strong> <strong>void</strong> setPrice(<strong>float</strong> price) {</p> <p><strong>this</strong>.price = price;</p> <p>}</p> <p>@Override</p> <p><strong>public</strong> String toString() {</p> <p><strong>return</strong> "Book [name=" + name + ", price=" + price + "]";</p> <p>}</p> <p>}</p> <p><strong>4.Sax</strong><strong>解析XML的事件处理类:</strong></p> <p>Sax的事件处理类必须实现ContentHandler接口,但我们在这个例子中不需要使用到ContentHandler接口的所有方法,我们仅需要其中的3个方法。所以Sax为我们提供了一个没有进行任何操作的ContentHandler实现类DefaultHandler。我们直接继承DefaultHandler类,并重写我们需要的方法即可。</p> <p><strong>package</strong> com.changcheng.androidxml.xml;</p> <p><strong>import</strong> java.util.ArrayList;</p> <p><strong>import</strong> java.util.List;</p> <p><strong>import</strong> org.xml.sax.Attributes;</p> <p><strong>import</strong> org.xml.sax.SAXException;</p> <p><strong>import</strong> org.xml.sax.helpers.DefaultHandler;</p> <p><strong>import</strong> com.changcheng.androidxml.entity.Book;</p> <p><strong>public</strong> <strong>class</strong> SaxXmlContentHandler <strong>extends</strong> DefaultHandler {</p> <p><strong>private</strong> List books;</p> <p><strong>private</strong> Book book;</p> <p><strong>private</strong> String tagName;</p> <p><strong>public</strong> List getBooks() {</p> <p><strong>return</strong> books;</p> <p>}</p> <p>/**</p> <p>* 接收文档的开始的通知。</p> <p>*/</p> <p>@Override</p> <p><strong>public</strong> <strong>void</strong> startDocument() <strong>throws</strong> SAXException {</p> <p><strong>this</strong>.books = <strong>new</strong> ArrayList();</p> <p>}</p> <p>/**</p> <p>* 接收字符数据的通知。</p> <p>*/</p> <p>@Override</p> <p><strong>public</strong> <strong>void</strong> characters(<strong>char</strong>[] ch, <strong>int</strong> start, <strong>int</strong> length)</p> <p><strong>throws</strong> SAXException {</p> <p><strong>if</strong> (<strong>this</strong>.tagName != <strong>null</strong>) {</p> <p>String data = <strong>new</strong> String(ch, start, length);</p> <p><strong>if</strong> (<strong>this</strong>.tagName.equals("name")) {</p> <p><strong>this</strong>.book.setName(data);</p> <p>} <strong>else</strong> <strong>if</strong> (<strong>this</strong>.tagName.equals("price")) {</p> <p><strong>this</strong>.book.setPrice(Float.<em>parseFloat</em>(data));</p> <p>}</p> <p>}</p> <p>}</p> <p>/**</p> <p>* 接收元素开始的通知。</p> <p>* namespaceURI:元素的命名空间</p> <p>* localName:元素的本地名称(不带前缀)</p> <p>* qName:元素的限定名(带前缀)</p> <p>* <span style="text-decoration: underline;">atts</span>:元素的属性集合</p> <p>*/</p> <p>@Override</p> <p><strong>public</strong> <strong>void</strong> startElement(String uri, String localName, String qName,</p> <p>Attributes attributes) <strong>throws</strong> SAXException {</p> <p><strong>if</strong> (localName.equals("book")) {</p> <p>book = <strong>new</strong> Book();</p> <p>book.setId(Integer.<em>parseInt</em>(attributes.getValue(0)));</p> <p>}</p> <p><strong>this</strong>.tagName = localName;</p> <p>}</p> <p>/**</p> <p>* 接收文档的结尾的通知。</p> <p>* <span style="text-decoration: underline;">uri</span>:元素的命名空间</p> <p>* localName:元素的本地名称(不带前缀)</p> <p>* name:元素的限定名(带前缀)</p> <p>*/</p> <p>@Override</p> <p><strong>public</strong> <strong>void</strong> endElement(String uri, String localName, String qName)</p> <p><strong>throws</strong> SAXException {</p> <p><strong>if</strong> (localName.equals("book")) {</p> <p><strong>this</strong>.books.add(<strong>this</strong>.book);</p> <p>}</p> <p><strong>this</strong>.tagName = <strong>null</strong>;</p> <p>}</p> <p>}</p> <p><strong>5.</strong><strong>编写测试Sax解析XML的类</strong></p> <p>在创建工程时,生成的AndroidXML.java,并没有被使用到。因为我们使用Android的单元测试,运行上面的程序。</p> <p>编写Android单元测试类:</p> <p><strong>package</strong> com.changcheng.androidxml.test;</p> <p><strong>import</strong> java.io.InputStream;</p> <p><strong>import</strong> java.io.StringWriter;</p> <p><strong>import</strong> java.util.ArrayList;</p> <p><strong>import</strong> java.util.List;</p> <p><strong>import</strong> com.changcheng.androidxml.entity.Book;</p> <p><strong>import</strong> com.changcheng.androidxml.xml.AndoridSaxXml;</p> <p><strong>import</strong> com.changcheng.androidxml.xml.AndroidPullXML;</p> <p><strong>import</strong> android.test.AndroidTestCase;</p> <p><strong>import</strong> android.util.Log;</p> <p><strong>public</strong> <strong>class</strong> TestAndroidXML <strong>extends</strong> AndroidTestCase {</p> <p><strong>private</strong> <strong>static</strong> <strong>final</strong> String <em>TAG</em> = "TestAndroidXML";</p> <p>/**</p> <p>* 测试<span style="text-decoration: underline;">Sax</span>解析XML</p> <p>* <strong>@throws</strong> Throwable</p> <p>*/</p> <p><strong>public</strong> <strong>void</strong> testAndroidSaxReadXML() <strong>throws</strong> Throwable{</p> <p>InputStream file = <strong>this</strong>.getClass().getClassLoader().getResourceAsStream("books.xml");</p> <p><strong>try</strong> {</p> <p>List books = AndoridSaxXml.<em>readXML</em>(file);</p> <p>Log.<em>i</em>(<em>TAG</em>, books.toString());</p> <p>} <strong>catch</strong> (Exception e) {</p> <p>Log.<em>e</em>(<em>TAG</em>, e.toString());</p> <p>}</p> <p>}</p> <p>}</p> <p>测试类必须继承自AndroidTestCase类,Android的单元测试使用的是JUnit3,所以在我们的测试方法名称要以test开头。</p> <p>再编写一个AndoridSaxXml(测试类中使用到的)类:</p> <p><strong>package</strong> com.changcheng.androidxml.xml;</p> <p><strong>import</strong> java.io.InputStream;</p> <p><strong>import</strong> java.util.List;</p> <p><strong>import</strong> javax.xml.parsers.SAXParser;</p> <p><strong>import</strong> javax.xml.parsers.SAXParserFactory;</p> <p><strong>import</strong> com.changcheng.androidxml.entity.Book;</p> <p><strong>public</strong> <strong>class</strong> AndoridSaxXml {</p> <p><strong>public</strong> <strong>static</strong> List readXML(InputStream inputStream) <strong>throws</strong> Exception {</p> <p>// 创建<span style="text-decoration: underline;">Sax</span>解析</p> <p>SAXParserFactory saxParFac = SAXParserFactory.<em>newInstance</em>();</p> <p>SAXParser saxParser = saxParFac.newSAXParser();</p> <p>SaxXmlContentHandler handler = <strong>new</strong> SaxXmlContentHandler();</p> <p>// 解析XML文件</p> <p>saxParser.parse(inputStream, handler);</p> <p>inputStream.close();</p> <p><strong>return</strong> handler.getBooks();</p> <p>}</p> <p>}</p> <p><strong>6.</strong><strong>运行测试</strong></p> <p>在outline面板中的testAndroidSaxReadXML方法或在TestAndroidXML类的testAndroidSaxReadXML方法上右键->Debug As->Android Junit Test。运行结束后在LogCat面板中查看运行结束。</p> <p>关于使用Sax生成XML文档,我在此就不做总结了。下面的Pull技术才是我们进行Android开发的重点。</p> <p><strong>二、Pull解析技术</strong></p> <p>Pull解析技术与Sax解析技术原理相同,但比Sax解析简单,它们的解析速度和占用的资源差不多。Android内部使用的XML解析技术正是Pull,Android官方推荐开发者们使用Pull解析技术。Pull解析技术是第三方开发的开源技术,它同样可以应用于JavaSE开发。下面我们使用Pull解析技术解析XML文件,然后再使用Pull技术生成XML文件。</p> <p><strong>Pull</strong><strong>解析XML文档</strong></p> <p><strong>1.XML</strong><strong>文件</strong></p> <p>依然使用上面的books.xml</p> <p><strong>2.XML</strong><strong>文档对应的实体Book</strong></p> <p>依然使用上面的Book.java</p> <p><strong>3.Pull</strong><strong>解析XML类</strong></p> <p><strong>package</strong> com.changcheng.androidxml.xml;</p> <p><strong>import</strong> java.io.InputStream;</p> <p><strong>import</strong> java.io.Writer;</p> <p><strong>import</strong> java.util.ArrayList;</p> <p><strong>import</strong> java.util.List;</p> <p><strong>import</strong> org.xmlpull.v1.XmlPullParser;</p> <p><strong>import</strong> org.xmlpull.v1.XmlPullParserFactory;</p> <p><strong>import</strong> org.xmlpull.v1.XmlSerializer;</p> <p><strong>import</strong> android.util.Xml;</p> <p><strong>import</strong> com.changcheng.androidxml.entity.Book;</p> <p><strong>public</strong> <strong>class</strong> AndroidPullXML {</p> <p><strong>public</strong> <strong>static</strong> List readXML(InputStream inputStream,</p> <p>String inputEncoding) <strong>throws</strong> Exception {</p> <p>// 创建Pull解析</p> <p>XmlPullParserFactory pullParserFactory = XmlPullParserFactory</p> <p>.<em>newInstance</em>();</p> <p>XmlPullParser pullParser = pullParserFactory.newPullParser();</p> <p>// 解析XML</p> <p>pullParser.setInput(inputStream, inputEncoding);</p> <p>// 开始</p> <p><strong>int</strong> eventType = pullParser.getEventType();</p> <p>List books = <strong>null</strong>;</p> <p>Book book = <strong>null</strong>;</p> <p><strong>while</strong> (eventType != XmlPullParser.<em>END_DOCUMENT</em>) {</p> <p>String nodeName = pullParser.getName();</p> <p><strong>switch</strong> (eventType) {</p> <p>// 文档开始</p> <p><strong>case</strong> XmlPullParser.<em>START_DOCUMENT</em>:</p> <p>books = <strong>new</strong> ArrayList();</p> <p><strong>break</strong>;</p> <p>// 节点开始</p> <p><strong>case</strong> XmlPullParser.<em>START_TAG</em>:</p> <p><strong>if</strong> ("book".equals(nodeName)) {</p> <p>book = <strong>new</strong> Book();</p> <p>book.setId(Integer</p> <p>.<em>parseInt</em>(pullParser.getAttributeValue(0)));</p> <p>} <strong>else</strong> <strong>if</strong> ("name".equals(nodeName)) {</p> <p>book.setName(pullParser.nextText());</p> <p>} <strong>else</strong> <strong>if</strong> ("price".equals(nodeName)) {</p> <p>book.setPrice(Float.<em>parseFloat</em>(pullParser.nextText()));</p> <p>}</p> <p><strong>break</strong>;</p> <p>// 节点结束</p> <p><strong>case</strong> XmlPullParser.<em>END_TAG</em>:</p> <p><strong>if</strong> ("book".equals(nodeName)) {</p> <p>books.add(book);</p> <p>book = <strong>null</strong>;</p> <p>}</p> <p><strong>break</strong>;</p> <p>}</p> <p>eventType = pullParser.next();</p> <p>}</p> <p><strong>return</strong> books;</p> <p>}</p> <p>}</p> <p><strong>4.</strong><strong>编写测试Pull解析XML类</strong></p> <p>在sax测试类TestAndroidXML中添加一个测试方法:</p> <p>/**</p> <p>* 测试Pull解析XML</p> <p>* <strong>@throws</strong> Throwable</p> <p>*/</p> <p><strong>public</strong> <strong>void</strong> testAndroidPullReadXML() <strong>throws</strong> Throwable {</p> <p>InputStream file = <strong>this</strong>.getClass().getClassLoader().getResourceAsStream("books.xml");</p> <p><strong>try</strong> {</p> <p>List books = AndroidPullXML.<em>readXML</em>(file, "UTF-8");</p> <p>Log.<em>i</em>(<em>TAG</em>, books.toString());</p> <p>} <strong>catch</strong> (Exception e) {</p> <p>Log.<em>e</em>(<em>TAG</em>, e.toString());</p> <p>}</p> <p>}</p> <p><strong>5.</strong><strong>运行测试</strong></p> <p>在outline面板中的testAndroidPullReadXML方法或在TestAndroidXML类的testAndroidPullReadXML方法上右键->Debug As->Android Junit Test。运行结束后在LogCat面板中查看运行结束。</p> <p><strong>Pull</strong><strong>生成XML文档</strong></p> <p>使用Pull生成上面的books.xml文档。</p> <p><strong>1.</strong><strong>在AndroidPullXML类中添加一个方法:</strong></p> <p><strong>public</strong> <strong>static</strong> <strong>void</strong> writeXML(Writer writer, List books)</p> <p><strong>throws</strong> Exception {</p> <p>// 创建XML生成器</p> <p>XmlSerializer writexml = Xml.<em>newSerializer</em>();</p> <p>writexml.setOutput(writer);</p> <p>// 生成XML文档</p> <p>writexml.startDocument("UTF-8", <strong>true</strong>);</p> <p>writexml.startTag("", "books");</p> <p><strong>for</strong> (Book book : books) {</p> <p>// name</p> <p>writexml.startTag("", "name");</p> <p>writexml.attribute("", "id", book.getId() + "");</p> <p>writexml.text(book.getName());</p> <p>writexml.endTag("", "name");</p> <p>// price</p> <p>writexml.startTag("", "price");</p> <p>writexml.text(book.getPrice() + "");</p> <p>writexml.endTag("", "price");</p> <p>}</p> <p>//</p> <p>writexml.endTag("", "books");</p> <p>}</p> <p><strong>2.</strong><strong>编写测试Pull生成XML方法</strong></p> <p>在sax测试类TestAndroidXML中添加一个测试方法:</p> <p>/**</p> <p>* 测试Pull生成XML</p> <p>* <strong>@throws</strong> Throwable</p> <p>*/</p> <p><strong>public</strong> <strong>void</strong> testAndroidPullWriteXML() <strong>throws</strong> Throwable {</p> <p>// 生成到内存中。(也可以生成到文件中,那就需要定义一个文件输出流。)</p> <p>StringWriter writer = <strong>new</strong> StringWriter();</p> <p>// 添加三本书</p> <p>List books = <strong>new</strong> ArrayList();</p> <p>books.add(<strong>new</strong> Book(1, "C", 89));</p> <p>books.add(<strong>new</strong> Book(1, "C++", 100));</p> <p>books.add(<strong>new</strong> Book(1, "Java", 87));</p> <p>books.add(<strong>new</strong> Book(1, "JavaEE", 95));</p> <p>// 生成XML</p> <p>AndroidPullXML.<em>writeXML</em>(writer, books);</p> <p>// 打印结果</p> <p>Log.<em>i</em>(<em>TAG</em>, books.toString());</p> <p>}</p> <p><strong>3.</strong><strong>运行测试</strong></p> <p>在outline面板中的testAndroidPullWriteXML方法或在TestAndroidXML类的testAndroidPullWriteXML方法上右键->Debug As->Android Junit Test。运行结束后在LogCat面板中查看运行结束。</p> <p>OK,使用Sax和Pull在Android中解析XML文档到此完成。在Andorid中还可以使用DOM技术,使用DOM技术解析在我们学习JavaWeb基础时,已经做了总结,在此就不再介绍了。</p>转载地址:http://edaji.baihongyu.com/