XML在各种开发中都广泛应用,Android也不例外。作为承载数据的一个重要角色,如何读写XML成为Android开发中一项重要的技能。今天就由我向大家介绍一下在Android平台下几种常见的XML解析和创建的方法。
在Android中,常见的XML解析器分别为SAX解析器、DOM解析器和PULL解析器,下面,我将一一向大家详细介绍。 SAX解析器:
SAX(Simple API for XML)解析器是一种基于事件的解析器,它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的。当事件源产生事件后,调用事件处理器相应的处理方法,一个事件就可以得到处理。在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事件处理器才能够根据提供的事件信息来决定自己的行为。
SAX解析器的优点是解析速度快,占用内存少。非常适合在Android移动设备中使用。 DOM解析器:
DOM是基于树形结构的的节点或信息片段的集合,允许开发人员使用DOM API遍历XML树、检索所需数据。分析该结构通常需要加载整个文档和构造树形结构,然后才可以检索和更新节点信息。
由于DOM在内存中以树形结构存放,因此检索和更新效率会更高。但是对于特别大的文档,解析和加载整个文档将会很耗资源。 PULL解析器:
PULL解析器的运行方式和SAX类似,都是基于事件的模式。不同的是,在PULL解析过程中,我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器。 以上三种解析器,都是非常实用的解析器,我将会一一介绍。我们将会使用这三种解析技术完成一项共同的任务。
我们新建一个项目,项目结构如下:
我会在项目的assets目录中放置一个XML文档books.xml,内容如下:
[xhtml] view plaincopy
1. 2. 4. 5. 9. 10. 14. 15.
然后我们分别使用以上三种解析技术解析文档,得到一个List [java] view plaincopy 1. package com.scott.xml.model; 2. 3. public class Book { 4. private int id; 5. private String name; 6. private float price; 7. 8. public int getId() { 9. return id; 10. } 11. 12. public void setId(int id) { 13. this.id = id; 14. } 15. 16. public String getName() { 17. return name; 18. } 19. 20. public void setName(String name) { 21. this.name = name; 22. } 23. 24. public float getPrice() { 25. return price; 26. } 27. 28. public void setPrice(float price) { 29. this.price = price; 30. } 31. 32. @Override 33. public String toString() { 34. return \"id:\" + id + \ + name + \ + price; 35. } 36. } 最后,我们还要把这个集合对象中的数据生成一个新的XML文档,如图: 生成的XML结构跟原始文档略有不同,是下面这种格式: [xhtml] view plaincopy 1. 2. 3. 4. 7. 8. 11. 12. 接下来,就该介绍操作过程了,我们先为解析器定义一个BookParser接口,每种类型的解析器需要实现此接口。BookParser.java代码如下: [java] view plaincopy 1. package com.scott.xml.parser; 2. 3. import java.io.InputStream; 4. import java.util.List; 5. 6. import com.scott.xml.model.Book; 7. 8. public interface BookParser { 9. /** 10. * 解析输入流 得到Book对象集合 11. * @param is 12. * @return 13. * @throws Exception 14. */ 15. public List 18. * 序列化Book对象集合 得到XML形式的字符串 19. * @param books 20. * @return 21. * @throws Exception 22. */ 23. public String serialize(List 好了,我们就该一个一个的实现该接口,完成我们的解析过程。 使用SAX解析器: SaxBookParser.java代码如下: [c-sharp] view plaincopy 1. package com.scott.xml.parser; 2. 3. import java.io.InputStream; 4. import java.io.StringWriter; 5. import java.util.ArrayList; 6. import java.util.List; 7. 8. import javax.xml.parsers.SAXParser; 9. import javax.xml.parsers.SAXParserFactory; 10. import javax.xml.transform.OutputKeys; 11. import javax.xml.transform.Result; 12. import javax.xml.transform.Transformer; 13. import javax.xml.transform.TransformerFactory; 14. import javax.xml.transform.sax.SAXTransformerFactory; 15. import javax.xml.transform.sax.TransformerHandler; 16. import javax.xml.transform.stream.StreamResult; 17. 18. import org.xml.sax.Attributes; 19. import org.xml.sax.SAXException; 20. import org.xml.sax.helpers.AttributesImpl; 21. import org.xml.sax.helpers.DefaultHandler; 22. 23. import com.scott.xml.model.Book; 24. 25. public class SaxBookParser implements BookParser { 26. 27. @Override 28. public List 29. SAXParserFactory factory = SAXParserFactory.newInstance(); //取得 SAXParserFactory实例 30. SAXParser parser = factory.newSAXParser(); //从 factory获取SAXParser实例 31. MyHandler handler = new MyHandler(); //实例化 自定义Handler 32. parser.parse(is, handler); //根据自 定义Handler规则解析输入流 33. return handler.getBooks(); 34. } 35. 36. @Override 37. public String serialize(List 38. SAXTransformerFactory factory = (SAXTransformerFactory) TransformerF actory.newInstance();//取得SAXTransformerFactory实例 39. TransformerHandler handler = factory.newTransformerHandler(); //从factory获取TransformerHandler实例 40. Transformer transformer = handler.getTransformer(); //从handler获取Transformer实例 41. transformer.setOutputProperty(OutputKeys.ENCODING, \"UTF-8\"); // 设置输出采用的编码方式 42. transformer.setOutputProperty(OutputKeys.INDENT, \"yes\"); // 是否自动添加额外的空白 43. transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, \"no\") ; // 是否忽略XML声明 44. 45. StringWriter writer = new StringWriter(); 46. Result result = new StreamResult(writer); 47. handler.setResult(result); 48. 49. String uri = \"\"; //代表命名空间的URI 当URI无值时 须置为空字符串 50. String localName = \"\"; //命名空间的本地名称(不包含前缀) 当没有进行命名 空间处理时 须置为空字符串 51. 52. handler.startDocument(); 53. handler.startElement(uri, localName, \"books\", null); . 55. AttributesImpl attrs = new AttributesImpl(); //负责存放元素的属性信 息 56. char[] ch = null; 57. for (Book book : books) { 58. attrs.clear(); //清空属性列表 59. attrs.addAttribute(uri, localName, \"id\", \"string\", String.valueO f(book.getId()));//添加一个名为id的属性(type影响不大,这里设为string) 60. handler.startElement(uri, localName, \"book\", attrs); //开始一 个book元素 关联上面设定的id属性 61. 62. handler.startElement(uri, localName, \"name\", null); //开始一个 name元素 没有属性 63. ch = String.valueOf(book.getName()).toCharArray(); . handler.characters(ch, 0, ch.length); //设置name元素的文本节 点 65. handler.endElement(uri, localName, \"name\"); 66. 67. handler.startElement(uri, localName, \"price\", null);//开始一个 price元素 没有属性 68. ch = String.valueOf(book.getPrice()).toCharArray(); 69. handler.characters(ch, 0, ch.length); //设置price元素的文本节 点 70. handler.endElement(uri, localName, \"price\"); 71. 72. handler.endElement(uri, localName, \"book\"); 73. } 74. handler.endElement(uri, localName, \"books\"); 75. handler.endDocument(); 76. 77. return writer.toString(); 78. } 79. 80. //需要重写DefaultHandler的方法 81. private class MyHandler extends DefaultHandler { 82. 83. private List 85. private StringBuilder builder; 86. 87. //返回解析后得到的Book对象集合 88. public List 92. @Override 93. public void startDocument() throws SAXException { 94. super.startDocument(); 95. books = new ArrayList 99. @Override 100. public void startElement(String uri, String localName, String qName , Attributes attributes) throws SAXException { 101. super.startElement(uri, localName, qName, attributes); 102. if (localName.equals(\"book\")) { 103. book = new Book(); 104. } 105. builder.setLength(0); //将字符长度设置为0 以便重新开始读取元素内 的字符节点 106. } 107. 108. @Override 109. public void characters(char[] ch, int start, int length) throws SAX Exception { 110. super.characters(ch, start, length); 111. builder.append(ch, start, length); //将读取的字符数组追加到 builder中 112. } 113. 114. @Override 115. public void endElement(String uri, String localName, String qName) throws SAXException { 116. super.endElement(uri, localName, qName); 117. if (localName.equals(\"id\")) { 118. book.setId(Integer.parseInt(builder.toString())); 119. } else if (localName.equals(\"name\")) { 120. book.setName(builder.toString()); 121. } else if (localName.equals(\"price\")) { 122. book.setPrice(Float.parseFloat(builder.toString())); 123. } else if (localName.equals(\"book\")) { 124. books.add(book); 125. } 126. } 127. } 128. } 代码中,我们定义了自己的事件处理逻辑,重写了DefaultHandler的几个重要的事件方法。下面我为大家着重介绍一下DefaultHandler的相关知识。DefaultHandler是一个事件处理器,可以接收解析器报告的所有事件,处理所发现的数据。它实现了EntityResolver接口、DTDHandler接口、ErrorHandler接口和ContentHandler接口。这几个接口代表不同类型的事件处理器。我们着重介绍一下ContentHandler接口。结构如图: 这几个比较重要的方法已被我用红线标注,DefaultHandler实现了这些方法,但在方法体内没有做任何事情,因此我们在使用时必须覆写相关的方法。最重要的是startElement方法、characters方法和endElement方法。当执行文档时遇到起始节点,startElement方法将会被调用,我们可以获取起始节点相关信息;然后characters方法被调用,我们可以获取节点内的文本信息;最后endElement方法被调用,我们可以做收尾的相关操作。 最后,我们需要调用SAX解析程序,这个步骤在MainActivity中完成: [java] view plaincopy 1. package com.scott.xml; 2. 3. import java.io.FileOutputStream; 4. import java.io.InputStream; 5. import java.util.List; 6. 7. import android.app.Activity; 8. import android.content.Context; 9. import android.os.Bundle; 10. import android.util.Log; 11. import android.view.View; 12. import android.widget.Button; 13. 14. import com.scott.xml.model.Book; 15. import com.scott.xml.parser.BookParser; 16. import com.scott.xml.parser.SaxBookParser; 17. 18. public class MainActivity extends Activity { 19. 20. private static final String TAG = \"XML\"; 21. 22. private BookParser parser; 23. private List 25. @Override 26. public void onCreate(Bundle savedInstanceState) { 27. super.onCreate(savedInstanceState); 28. setContentView(R.layout.main); 29. 30. Button readBtn = (Button) findViewById(R.id.readBtn); 31. Button writeBtn = (Button) findViewById(R.id.writeBtn); 32. 33. readBtn.setOnClickListener(new View.OnClickListener() { 34. @Override 35. public void onClick(View v) { 36. try { 37. InputStream is = getAssets().open(\"books.xml\"); 38. parser = new SaxBookParser(); //创建SaxBookParser实例 39. books = parser.parse(is); //解析输入流 40. for (Book book : books) { 41. Log.i(TAG, book.toString()); 42. } 43. } catch (Exception e) { 44. Log.e(TAG, e.getMessage()); 45. } 46. } 47. }); 48. writeBtn.setOnClickListener(new View.OnClickListener() { 49. @Override 50. public void onClick(View v) { 51. try { 52. String xml = parser.serialize(books); //序列化 53. FileOutputStream fos = openFileOutput(\"books.xml\", Conte xt.MODE_PRIVATE); . fos.write(xml.getBytes(\"UTF-8\")); 55. } catch (Exception e) { 56. Log.e(TAG, e.getMessage()); 57. } 58. } 59. }); 60. } 61. } 界面就两个按钮,顺便给大家贴上: 点击“readXML”按钮,将会调用SAX解析器解析文档,并在日志台打印相关信息: 然后再点击“writeXML”按钮,将会在该应用包下的files目录生成一个books.xml文件: 使用DOM解析器: DomBookParser.java代码如下: [java] view plaincopy 1. package com.scott.xml.parser; 2. 3. import java.io.InputStream; 4. import java.io.StringWriter; 5. import java.util.ArrayList; 6. import java.util.List; 7. 8. import javax.xml.parsers.DocumentBuilder; 9. import javax.xml.parsers.DocumentBuilderFactory; 10. import javax.xml.transform.OutputKeys; 11. import javax.xml.transform.Result; 12. import javax.xml.transform.Source; 13. import javax.xml.transform.Transformer; 14. import javax.xml.transform.TransformerFactory; 15. import javax.xml.transform.dom.DOMSource; 16. import javax.xml.transform.stream.StreamResult; 17. 18. import org.w3c.dom.Document; 19. import org.w3c.dom.Element; 20. import org.w3c.dom.Node; 21. import org.w3c.dom.NodeList; 22. 23. import com.scott.xml.model.Book; 24. 25. public class DomBookParser implements BookParser { 26. 27. @Override 28. public List 30. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance( ); //取得DocumentBuilderFactory实例 31. DocumentBuilder builder = factory.newDocumentBuilder(); //从factory 获取DocumentBuilder实例 32. Document doc = builder.parse(is); //解析输入流 得到Document实例 33. Element rootElement = doc.getDocumentElement(); 34. NodeList items = rootElement.getElementsByTagName(\"book\"); 35. for (int i = 0; i < items.getLength(); i++) { 36. Book book = new Book(); 37. Node item = items.item(i); 38. NodeList properties = item.getChildNodes(); 39. for (int j = 0; j < properties.getLength(); j++) { 40. Node property = properties.item(j); 41. String nodeName = property.getNodeName(); 42. if (nodeName.equals(\"id\")) { 43. book.setId(Integer.parseInt(property.getFirstChild().get NodeValue())); 44. } else if (nodeName.equals(\"name\")) { 45. book.setName(property.getFirstChild().getNodeValue()); 46. } else if (nodeName.equals(\"price\")) { 47. book.setPrice(Float.parseFloat(property.getFirstChild(). getNodeValue())); 48. } 49. } 50. books.add(book); 51. } 52. return books; 53. } . 55. @Override 56. public String serialize(List 57. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance( ); 58. DocumentBuilder builder = factory.newDocumentBuilder(); 59. Document doc = builder.newDocument(); //由builder创建新文档 60. 61. Element rootElement = doc.createElement(\"books\"); 62. 63. for (Book book : books) { . Element bookElement = doc.createElement(\"book\"); 65. bookElement.setAttribute(\"id\", book.getId() + \"\"); 66. 67. Element nameElement = doc.createElement(\"name\"); 68. nameElement.setTextContent(book.getName()); 69. bookElement.appendChild(nameElement); 70. 71. Element priceElement = doc.createElement(\"price\"); 72. priceElement.setTextContent(book.getPrice() + \"\"); 73. bookElement.appendChild(priceElement); 74. 75. rootElement.appendChild(bookElement); 76. } 77. 78. doc.appendChild(rootElement); 79. 80. TransformerFactory transFactory = TransformerFactory.newInstance();/ /取得TransformerFactory实例 81. Transformer transformer = transFactory.newTransformer(); //从 transFactory获取Transformer实例 82. transformer.setOutputProperty(OutputKeys.ENCODING, \"UTF-8\"); // 设置输出采用的编码方式 83. transformer.setOutputProperty(OutputKeys.INDENT, \"yes\"); // 是否自动添加额外的空白 84. transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, \"no\") ; // 是否忽略XML声明 85. 86. StringWriter writer = new StringWriter(); 87. 88. Source source = new DOMSource(doc); //表明文档来源是doc . Result result = new StreamResult(writer);//表明目标结果为writer 90. transformer.transform(source, result); //开始转换 91. 92. return writer.toString(); 93. } 94. 95. } 然后再MainActivity中只需改一个地方: [java] view plaincopy 1. readBtn.setOnClickListener(new View.OnClickListener() { 2. @Override 3. public void onClick(View v) { 4. try { 5. InputStream is = getAssets().open(\"books.xml\"); 6. // parser = new SaxBookParser(); 7. parser = new DomBookParser(); 8. books = parser.parse(is); 9. for (Book book : books) { 10. Log.i(TAG, book.toString()); 11. } 12. } catch (Exception e) { 13. Log.e(TAG, e.getMessage()); 14. } 15. } 16. ); 执行结果是一样的。 使用PULL解析器: PullBookParser.java代码如下: [java] view plaincopy 1. package com.scott.xml.parser; 2. 3. import java.io.InputStream; 4. import java.io.StringWriter; 5. import java.util.ArrayList; 6. import java.util.List; 7. 8. import org.xmlpull.v1.XmlPullParser; 9. import org.xmlpull.v1.XmlSerializer; 10. 11. import android.util.Xml; 12. 13. import com.scott.xml.model.Book; 14. 15. public class PullBookParser implements BookParser { 16. 17. @Override 18. public List 22. // XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 23. // XmlPullParser parser = factory.newPullParser(); 24. 25. XmlPullParser parser = Xml.newPullParser(); //由android.util.Xml创建 一个XmlPullParser实例 26. parser.setInput(is, \"UTF-8\"); //设置输入流 并指明编码方 式 27. 28. int eventType = parser.getEventType(); 29. while (eventType != XmlPullParser.END_DOCUMENT) { 30. switch (eventType) { 31. case XmlPullParser.START_DOCUMENT: 32. books = new ArrayList 34. case XmlPullParser.START_TAG: 35. if (parser.getName().equals(\"book\")) { 36. book = new Book(); 37. } else if (parser.getName().equals(\"id\")) { 38. eventType = parser.next(); 39. book.setId(Integer.parseInt(parser.getText())); 40. } else if (parser.getName().equals(\"name\")) { 41. eventType = parser.next(); 42. book.setName(parser.getText()); 43. } else if (parser.getName().equals(\"price\")) { 44. eventType = parser.next(); 45. book.setPrice(Float.parseFloat(parser.getText())); 46. } 47. break; 48. case XmlPullParser.END_TAG: 49. if (parser.getName().equals(\"book\")) { 50. books.add(book); 51. book = null; 52. } 53. break; . } 55. eventType = parser.next(); 56. } 57. return books; 58. } 59. 60. @Override 61. public String serialize(List 62. // XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 63. // XmlSerializer serializer = factory.newSerializer(); . 65. XmlSerializer serializer = Xml.newSerializer(); //由android.util.Xml 创建一个XmlSerializer实例 66. StringWriter writer = new StringWriter(); 67. serializer.setOutput(writer); //设置输出方向为writer 68. serializer.startDocument(\"UTF-8\", true); 69. serializer.startTag(\"\", \"books\"); 70. for (Book book : books) { 71. serializer.startTag(\"\", \"book\"); 72. serializer.attribute(\"\", \"id\", book.getId() + \"\"); 73. 74. serializer.startTag(\"\", \"name\"); 75. serializer.text(book.getName()); 76. serializer.endTag(\"\", \"name\"); 77. 78. serializer.startTag(\"\", \"price\"); 79. serializer.text(book.getPrice() + \"\"); 80. serializer.endTag(\"\", \"price\"); 81. 82. serializer.endTag(\"\", \"book\"); 83. } 84. serializer.endTag(\"\", \"books\"); 85. serializer.endDocument(); 86. 87. return writer.toString(); 88. } . } 然后再对MainActivity做以下更改: [java] view plaincopy 1. readBtn.setOnClickListener(new View.OnClickListener() { 2. @Override 3. public void onClick(View v) { 4. try { 5. InputStream is = getAssets().open(\"books.xml\"); 6. // parser = new SaxBookParser(); 7. // parser = new DomBookParser(); 8. parser = new PullBookParser(); 9. books = parser.parse(is); 10. for (Book book : books) { 11. Log.i(TAG, book.toString()); 12. } 13. } catch (Exception e) { 14. Log.e(TAG, e.getMessage()); 15. } 16. } 17. }); 和其他两个执行结果都一样。 对于这三种解析器各有优点,我个人比较倾向于PULL解析器,因为SAX解析器操作起来太笨重,DOM不适合文档较大,内存较小的场景,唯有PULL轻巧灵活,速度快,占用内存小,使用非常顺手。读者也可以根据自己的喜好选择相应的解析技术。 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- yrrf.cn 版权所有 赣ICP备2024042794号-2
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务