xml解析(读取xml,保存文件到xml)

一时失言乱红尘 2022-09-23 03:51 383阅读 0赞

在Android中,实现对XML的解析有三种方式,分别为DOM解析器,SAX解析器和PULL解析器。

  • DOM解析器

DOM是基于树形结构的节点或信息片段的集合,允许开发人员使用DOM API遍历XML树,检索所需数据。

分析该结构通常需要加载整个文档和构造树形结构,然后才可以检索和更新节点信息。

Android完全支持DOM解析。利用DOM中的对象,可以对XML文档进行读取,搜索,修改,添加和删除等操作。

DOM的工作原理:使用DOM对XML文件进行操作时,首先要解析文件,将文件分为独立的元素,属性和注释等,

然后以节点树的形式在内存中对XML文件进行表示,就可以通过节点树访问文档的内容,并根据需要修改文档。

DOM实现时首先为XML文档的解析定义一组接口,解析器读入整个文档,然后构造一个驻留内存的树结构,

这样代码就可以使用DOM接口来操作整个树结构。

由于DOM在内存中以树形结构存放,因此检索和更新效率会更高。但是对于特别大的文档,解析和加载整个文档将会

很耗资源。当然,如果XML文件的内容比较小,采用DOM是可行的。

常用的DOM接口和类:

Document: 该接口定义分析并创建DOM文档的一系列方法,它是文档树的根,是操作DOM的基础。

Element: 该接口继承Node接口,提供了获取,修改XML元素名字和属性的方法。

Node: 该接口提供处理并获取节点和子节点值的方法。

NodeList: 提供获得节点个数和当前节点的方法。这样就可以迭代地访问各节点。

DOMParser: 该类是Apache的Xerces中的DOM解析器类,可直接解析XML文件。

示例:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <persons>
  3. <person id="1">
  4. <name>叶问</name>
  5. <age>23</age>
  6. </person>
  7. <person id="2">
  8. <name>李小龙</name>
  9. <age>17</age>
  10. </person>
  11. </persons>
  12. public class DomXMLReader {
  13. public static List<Person> readXML( InputStream inStream) {
  14. List<Person> persons = new ArrayList<Person>;
  15. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  16. try {
  17. DocumentBuilder builer = factory.newDocumentBuilder();
  18. Document dom = builder.parse(inStream);
  19. Element root = dom.getDocumentElement();
  20. NodeList items = root.getElementsByTagName("person");
  21. //查找所有person节点
  22. for (int i = 0; i < items.getLength(); i++) {
  23. Person person = new Person();
  24. //得到第一个person节点
  25. Element personNode = (Element) items.item(i);
  26. //获取person节点的id属性值
  27. person.setId(new Integer(personNode.getAttribute("id")));
  28. //获取person节点下的所有子节点(标签之间的空白节点和name/age元素)
  29. NodeList childsNodes = personNode.getChildNodews();
  30. for( int j =0; j < childsNodes.getLength(); j++) {
  31. Node node = (Node) childsNodes.item(j);
  32. //判断是否为元素类型
  33. if( node.getNodeType() == Node.ELEMENT_NODE) {
  34. Element childNode = (Element) node;
  35. if( "name".equals(childNode.getNodeName())) {
  36. //获取name元素下Text节点,然后从Text节点获取数据
  37. person.setName( childNode.getFirstChild().getNodeValue());
  38. } else if ("age".equals(childNode.getNodeName())) {
  39. person.setAge( new Short(childNode.getFirstChild().getNodeValue()));
  40. }
  41. }
  42. }
  43. persons.add(person);
  44. }
  45. inStream.close();
  46. } catch (Exception e) {
  47. e.printStackTrace();
  48. }
  49. return persons;
  50. }
  • SAX解析器:

SAX解析器是一种基于事件的解析器,事件驱动的流式解析方式是,从文件的开始顺序解析到文档结束,不可暂停或倒退。

它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的。当事件源产生事件后,调用事件处理器相应的处理方法,

一个事件就可以得到处理。在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事件处理器

才能根据提供的事件信息来决定自己的行为。

SAX解析器的优点是解析速度快,占用内存少。非常适合在Android移动设备中使用。

SAX的工作原理: 对文档进行顺序扫描,当扫描到文档(document)开始与结束,元素(element)开始与结束,文档(document)结束等

地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描直到文档结束。

在SAX接口中,事件源是org.xml.sax包中的XMLReader,它通过parser()方法来解析XML文档,并产生事件。

事件处理器是org.xml.sax包中ContentHandler, DTDHandler, ErrorHandler,以及EntityResolver这4个接口。

XMLReader通过相应事件处理器注册方法setXXXX()来完成的与ContentHandler, DTDHandler, ErrorHandler,

以及EntivityResolver这4个接口的连接。

常用的SAX接口和类:

  1. Attributes: 用于得到属性的个数,名字和值。
  2. ContentHandler: 定义与文档本身关联的事件(例如,开始和结束标记)。大多数应用程序都注册这些事件。
  3. DTDHandler: 定义与DTD关联的事件。它没有定义足够的事件来完整地报告DTD。如果需要对DTD进行语法分析,请使用可选的DeclHandler
  4. DeclHandlerSAX的扩展。不是所有的语法分析器都支持它。
  5. EntityResolver:定义与装入实体关联的事件。只有少数几个应用程序注册这些事件。
  6. ErrorHandler:定义错误事件。许多应用程序注册这些事件以便用它们自己的方式报错。
  7. DefaultHandler:它提供了这些接LI的缺省实现。在大多数情况下,为应用程序扩展DefaultHandler并覆盖相关的方法要比直接实现一个接口更容易。

2012-02-28_010539.jpg

示例:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <persons>
  3. <person id="23">
  4. <name>李明</name>
  5. <age>30</age>
  6. </person>
  7. <person id="20">
  8. <name>李向梅</name>
  9. <age>25</age>
  10. </person>
  11. </persons>
  12. public class Person implements Serializable{
  13. private Integer id;
  14. private String name;
  15. private Short age;
  16. public Person() {
  17. }
  18. public Person(String name, Short age) {
  19. super();
  20. this.name = name;
  21. this.age = age;
  22. }
  23. public Integer getId() {
  24. return id;
  25. }
  26. public void setId(Integer id) {
  27. this.id = id;
  28. }
  29. public String getName() {
  30. return name;
  31. }
  32. public void setName(String name) {
  33. this.name = name;
  34. }
  35. public Short getAge() {
  36. return age;
  37. }
  38. public void setAge(Short age) {
  39. this.age = age;
  40. }
  41. }
  42. public class XMLContenteHandler extends DefaultHandler {
  43. <span style="color:#000000;"> //临时变量,解决sax读取XML时不能读取换行符号后面的内容的问题;注意temp=""不能写成temp或temp=null,避免脏数据</span>
  44. private String temp="";
  45. private String preTag;
  46. private Person person;
  47. private List<Person> persons;
  48. public void startDocument() throws SAXException {
  49. persons = new ArrayList<Person>();
  50. }
  51. public void characters(char[] ch, int start, int length) throws SAXException {
  52. if(person != null) {
  53. String date = new String(ch, start, length);
  54. if("name".equals(preTag)){
  55. temp += date;
  56. } else if("age".equals(preTag)){
  57. temp += date;
  58. }
  59. }
  60. }
  61. public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
  62. if("person".equals(localName)){
  63. person = new Person();
  64. person.setId(attributes.getIndex("id"));
  65. }
  66. preTag = localName;
  67. }
  68. public void endElement( String uri, String localName, String name) throws SAXException {
  69. if(person != null && "name".equals(localName)) {
  70. person.setName(temp);
  71. temp="";
  72. } else if(person != null && "age".equals(localName)){
  73. person.setAge(new Short(temp));
  74. temp="";
  75. } else if(person != null && "person".equals(localName)) {
  76. persons.add(person);
  77. person = null;
  78. }
  79. preTag =null;
  80. }
  81. public List<person> getPersons() {
  82. return persons;
  83. }
  84. }
  85. public class SaxPersonService {
  86. // 业务层要对外抛出
  87. public static List<Person> readXML(InputStrean inStrean) throws Exception {
  88. SAXParserFactory spf = SAXParserFactory.newInstance();
  89. SAXParser saxParser = spf.newSAXParser();//创建解析器
  90. //设置解析器的相关特性,http://xnl.org/sax/features/namespaces = true;
  91. //表示开启命名空间特性
  92. //saxParser.setProperty("http://xnl.org/sax/features/namespaces", true);
  93. XMLContentHandler handler = new XMLContentHandler();
  94. saxParser.parse(inStream, handler);
  95. inStream.close();
  96. return handler.getPersons();
  97. }
  98. }
  99. public class SaxPersonServiceTest extends AndroidTestCase{
  100. private final String TAG = "SaxPersonServiceTest";
  101. public void testReadXML() throws Exception{
  102. //ljq.xml放在src目录下
  103. InputStream inputStream = SaxPersonServiceTest.class.getClassLoader().getResourceAsStream("ljq.xml");
  104. List<Person> persons = SaxPersonService.readXML(inputStream);
  105. for(Person person : persons){
  106. Log.i(TAG, person.getId() + " : " + person.getName() + " : " + person.getAge());
  107. }
  108. }
  109. }
  • PULL解析器

PULL解析器的运行方式和SAX类似,都是基于事件的模式。不同的是,在PULL解析过程中返回的是数字,且我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。

PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器,Android官方推荐开发者们使用Pull解析技术。Pull解析技术是第三方开发的开源技术,它同样可以应用于JavaSE开发。

PULL 的工作原理:XML pull提供了开始元素和结束元素。当某个元素开始时,我们可以调用parser.nextText从XML文档中提取所有字符数据。当解释到一个文档结束时,自动生成EndDocument事件。

读取XML

XmlPullParser pullParser = Xml.newPullParser();

pullParser.setInput(xml, “UTF-8”); // 为破解器添加要解析的xml数据

int event = pullParser.getEventType(); //开始读取,获取事件返回值

pullParser.getName(); // 获取节点名称

pullParser.getAttributeValue(0); // 获取第一个属性的值

pullParser.nextText(); //获取标签之后的节点内容

event = pullParser.next(); // 解析器遇到结束标签不会自动向下解析,需要调用此方法进行继续执行

保存文件到XML

  1. public static void save(List<Person> persons, OutputStream outStream)
  2. throws Exception, IllegalStateException, IOException {
  3. XmlSerializer serializer = Xml.newSerializer();//获取XML写入信息的序列化对象
  4. serializer.setOutput(outStream, "UTF-8");//设置要写入的OutputStream
  5. serializer.startDocument("UTF-8", true);//设置文档标签
  6. serializer.startTag(null, "persons");//设置开始标签,第一个参数为namespace
  7. for (Person person : persons) {
  8. serializer.startTag(null, "person");
  9. serializer.attribute(null, "id", person.getId().toString());
  10. serializer.startTag(null, "name");
  11. serializer.text(person.getName());
  12. serializer.endTag(null, "name");
  13. serializer.startTag(null, "age");
  14. serializer.text(person.getAge().toString());
  15. serializer.endTag(null, "age");
  16. serializer.endTag(null, "person");
  17. }
  18. serializer.endTag(null, "persons");
  19. serializer.endDocument();
  20. outStream.flush();
  21. outStream.close();
  22. }

发表评论

表情:
评论列表 (有 0 条评论,383人围观)

还没有评论,来说两句吧...

相关阅读