您的位置:首页 > 其它

DOM、SAX、PULL方式解析XML

2015-03-11 18:01 330 查看
DOM、SAX、PULL方式解析XML
实际编程中,我们经常需要用到XML文档,它能实现实体类对象的序列化保存,我们也很容易将XML文件内容反解成为实体类对象集合。下面的内容将介绍如何以DOM、SAX、PULL三种方式实现XML文件的解析。

我们以示例的方式方便讲解。

首先设定一个XML文件内容为,并将其保存到Android项目的assets文件夹中:

1. <?xml version="1.0" encoding="utf-8"?>
2. <persons>
3. <person>
4. <id>001</id>
5. <name>张三</name>
6. <sex></sex>
7. </person>
8. <person>
9. <id>002</id>
10. <name>李四</name>
11. <sex></sex>
12. </person>
13. <person>
14. <id>003</id>
15. <name>王二麻子</name>
16. <sex></sex>
17. </person>
18. </persons>

那么对应的实体类PersonBean.java的内容就是:

1. package com.example.bigbigboy.bean;
2. /**
3. *Created by BigBigBoy on 2015/3/11.
4. */
5. public class PersonBean {
6. private int id;
7. private String name;
8. private String sex;
9. public int getId() {
10. return id;}
11. public void setId(int id) {
12. this.id = id;}
13. public String getName() {
14. return name;}
15. public void setName(String name) {
16. this.name = name;}
17. public String getSex() {
18. return sex;}
19. public void setSex(String sex) {
20. this.sex = sex;}
21. @Override
22. public String toString() {
23. return "id--->" + id +"\nname--->" + name + "\nsex--->" + sex;}}

由于涉及到多种方式解析和序列化XML文件,但是我们主要面对两个方法,为了分离方法的调用和具体是实现的,我们这里定义一个接口XmlOperate,它包括解析和序列化两个方法:

1. package com.example.xml;
2. import com.example.bigbigboy.bean.PersonBean;
3. import java.io.InputStream;
4. import java.util.List;
5.
6. /**
7. *Created by BigBigBoy on 2015/3/11.
8. */
9. public interface XmlOperate {
10. /**
11. *解析输入流得到PersonBean对象集合
12. *@param is
13. *@return
14. *@throws Exception
15. */
16. public List<PersonBean>xmlParse(InputStream is) throws Exception;
17. /**
18. *序列化PersonBean对象集合得到XML形式的字符串
19. *@param persons
20. *@return
21. *@throws Exception
22. */
23. public StringxmlSerialize(List<PersonBean> persons) throws Exception;
24. }

为了直观的观察解析后的结果,我们创建一个MainActivity.class,并在界面中放置一个ListView来展示解析的结果,两个按钮,分别实现解析和序列化两个功能。界面布局如下:



其中解析按钮下的代码为:

1. public void onParseClick(View view) throwsException {
2. //XmlOperate xmlOperate = newSAX_Person();
3. //XmlOperate xmlOperate = newDOM_Person();
4. XmlOperate xmlOperate = newPULL_Person();
5. List<PersonBean> list =xmlOperate.xmlParse(getResources().getAssets().open("persons.xml"));
6. listViewAdapter = newListViewAdapter(this, list);
7. listView.setAdapter(listViewAdapter);
8. }

序列化下的按钮代码为:

1. public void onSaveClick(View view) throwsException {
2. XmlOperate xmlOperate = newSAX_Person();
3. //XmlOperate xmlOperate = newDOM_Person();
4. //XmlOperate xmlOperate = newPULL_Person();
5. List<PersonBean> list =xmlOperate.xmlParse(getResources().getAssets().open("persons.xml"));
6. Log.d("xmlSerialize",xmlOperate.xmlSerialize(list));
7. }

就这样,在我们还完全没有实现真正的代码解析和序列化功能的情况下,我们却已经完成了前面的使用部分代码,接下来我们只需要分别去实现DOM、SAX、PULL三种方式的解析和序列化功能就行了。

使用DOM解析器下的代码:

1. package com.example.xml.DOMOperate;
2. /**
3. *Created by BigBigBoy on 2015/3/11.
4. */
5. public class DOM_Person implements XmlOperate{
6. @Override
7. public List<PersonBean>xmlParse(InputStream is) throws Exception {
8. List<PersonBean> persons = newArrayList<PersonBean>();
9. DocumentBuilderFactory factory =DocumentBuilderFactory.newInstance(); //取得DocumentBuilderFactory实例
10. DocumentBuilder builder =factory.newDocumentBuilder(); //从factory获取DocumentBuilder实例
11. Document doc = builder.parse(is); //解析输入流得到Document实例
12. Element rootElement =doc.getDocumentElement();
13. NodeList items =rootElement.getElementsByTagName("person");
14. for (int i = 0; i <items.getLength(); i++) {
15. PersonBean person = newPersonBean();
16. Node item = items.item(i);
17. NodeList properties =item.getChildNodes();
18. for (int j = 0; j <properties.getLength(); j++) {
19. Node property = properties.item(j);
20. String nodeName =property.getNodeName();
21. if(nodeName.equals("id")) {
22. person.setId(Integer.parseInt(property.getFirstChild().getNodeValue()));
23. } else if(nodeName.equals("name")) {
24. person.setName(property.getFirstChild().getNodeValue());
25. } else if(nodeName.equals("sex")) {
26. person.setSex(property.getFirstChild().getNodeValue());
27. }
28. }
29. persons.add(person);
30. }
31. return persons;
32. }
33.
34. @Override
35. public StringxmlSerialize(List<PersonBean> persons) throws Exception {
36. DocumentBuilderFactory factory =DocumentBuilderFactory.newInstance();
37. DocumentBuilder builder =factory.newDocumentBuilder();
38. Document doc =builder.newDocument(); //由builder创建新文档
39. Element rootElement =doc.createElement("persons");
40. for (PersonBean person : persons) {
41. Element personElement =doc.createElement("person");
42. personElement.setAttribute("id",person.getId() + "");
43. Element nameElement =doc.createElement("name");
44. nameElement.setTextContent(person.getName());
45. personElement.appendChild(nameElement);
46. Element priceElement =doc.createElement("sex");
47. priceElement.setTextContent(person.getSex()+ "");
48. personElement.appendChild(priceElement);
49. rootElement.appendChild(personElement);
50. }
51. doc.appendChild(rootElement);
52. TransformerFactory transFactory =TransformerFactory.newInstance();//取得TransformerFactory实例
53. Transformer transformer =transFactory.newTransformer(); //从transFactory获取Transformer实例
54. transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8"); //设置输出采用的编码方式
55. transformer.setOutputProperty(OutputKeys.INDENT,"yes"); //是否自动添加额外的空白 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"no");
//是否忽略XML声明

56. StringWriter writer = newStringWriter();
57. Source source = new DOMSource(doc); //表明文档来源是doc
58. Result result = newStreamResult(writer);//表明目标结果为writer
59. transformer.transform(source,result); //开始转换
60. return writer.toString();
61. }}

使用SAX解析器下的代码:(由于SAX解析器的事件+处理者分离模型,我们将它分为SAX_Person和SAXPersonHandler两个类)

1. package com.example.xml.SAXOperate;
2. /**
3. *Created by BigBigBoy on 2015/3/11.
4. */
5. public class SAX_Person implements XmlOperate{
6. @Override
7. public List<PersonBean>xmlParse(InputStream is) throws Exception {
8. SAXParserFactory factory =SAXParserFactory.newInstance(); //取得SAXParserFactory实例
9. SAXParser parser = factory.newSAXParser(); //从factory获取SAXParser实例
10. SAXPersonHandler handler = newSAXPersonHandler(); //实例化自定义Handler
11. parser.parse(is, handler); //根据自定义Handler规则解析输入流
12. return handler.getPersons();
13. }
14.
15. @Override
16. public StringxmlSerialize(List<PersonBean> persons) throws Exception {
17. SAXTransformerFactory factory =(SAXTransformerFactory) TransformerFactory.newInstance();//取得SAXTransformerFactory实例
18. TransformerHandler handler =factory.newTransformerHandler(); //从factory获取TransformerHandler实例
19. Transformer transformer =handler.getTransformer(); //从handler获取Transformer实例
20. transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8"); //设置输出采用的编码方式
21. transformer.setOutputProperty(OutputKeys.INDENT,"yes"); //是否自动添加额外的空白
22. transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"no"); //是否忽略XML声明
23.
24. StringWriter writer = newStringWriter();
25. Result result = newStreamResult(writer);
26. handler.setResult(result);
27.
28. String uri = ""; //代表命名空间的URI当URI无值时须置为空字符串
29. String localName = ""; //命名空间的本地名称(不包含前缀)当没有进行命名空间处理时须置为空字符串
30.
31. handler.startDocument();
32. handler.startElement(uri, localName,"persons", null);
33.
34. AttributesImpl attrs = newAttributesImpl(); //负责存放元素的属性信息
35. char[] ch = null;
36. for (PersonBean person : persons) {
37. attrs.clear(); //清空属性列表
38. attrs.addAttribute(uri, localName,"id", "string", String.valueOf(person.getId()));//添加一个名为id的属性(type影响不大,这里设为string)
39. handler.startElement(uri,localName, "person", attrs); //开始一个person元素关联上面设定的id属性
40.
41. handler.startElement(uri, localName,"name", null); //开始一个name元素没有属性
42. ch =String.valueOf(person.getName()).toCharArray();
43. handler.characters(ch, 0,ch.length); //设置name元素的文本节点
44. handler.endElement(uri, localName,"name");
45.
46. handler.startElement(uri,localName, "sex", null);//开始一个sex元素没有属性
47. ch =String.valueOf(person.getSex()).toCharArray();
48. handler.characters(ch, 0,ch.length); //设置sex元素的文本节点
49. handler.endElement(uri, localName,"sex");
50.
51. handler.endElement(uri, localName,"person");
52. }
53. handler.endElement(uri, localName,"persons");
54. handler.endDocument();
55. return writer.toString();
56. }
57. }

SAXPersonHandler类代码:

1.
package com.example.xml.SAXOperate;

2.
3. /**
4. *Created by BigBigBoy on 2015/3/11.
5. */
6. public class SAXPersonHandler extendsDefaultHandler {
7.
8. private List<PersonBean> persons;
9. private PersonBean person;
10. private StringBuilder builder;
11.
12. //返回解析后得到的Person对象集合
13. public List<PersonBean> getPersons(){
14. return persons;
15. }
16.
17. @Override
18. public void startDocument() throwsSAXException {
19. super.startDocument();
20. persons = newArrayList<PersonBean>();
21. builder = new StringBuilder();
22. }
23.
24. @Override
25. public void startElement(String uri, StringlocalName, String qName, Attributes attributes) throws SAXException {
26. super.startElement(uri, localName,qName, attributes);
27. if(localName.equals("person")) {
28. person = new PersonBean();
29. }
30. builder.setLength(0); //将字符长度设置为0以便重新开始读取元素内的字符节点
31. }
32.
33. @Override
34. public void characters(char[] ch, intstart, int length) throws SAXException {
35. super.characters(ch, start, length);
36. builder.append(ch, start, length); //将读取的字符数组追加到builder中
37. }
38.
39. @Override
40. public void endElement(String uri, StringlocalName, String qName) throws SAXException {
41. super.endElement(uri, localName,qName);
42. if (localName.equals("id")) {
43. person.setId(Integer.parseInt(builder.toString()));
44. } else if(localName.equals("name")) {
45. person.setName(builder.toString());
46. } else if(localName.equals("sex")) {
47. person.setSex(builder.toString());
48. } else if(localName.equals("person")) {
49. persons.add(person);
50. }
51. }
52. }

使用PULL解析器的代码:

1. package com.scott.xml.parser;
2. public class PullBookParser implementsBookParser {
3. @Override
4. public List<Book> parse(InputStreamis) throws Exception {
5. List<Book> books = null;
6. Book book = null;
7. // XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
8. // XmlPullParser parser = factory.newPullParser();
9. XmlPullParser parser =Xml.newPullParser(); //由android.util.Xml创建一个XmlPullParser实例
10. parser.setInput(is,"UTF-8"); //设置输入流并指明编码方式

11. int eventType =parser.getEventType();
12. while (eventType !=XmlPullParser.END_DOCUMENT) {
13. switch (eventType) {
14. caseXmlPullParser.START_DOCUMENT:
15. books = newArrayList<Book>();
16. break;
17. case XmlPullParser.START_TAG:
18. if(parser.getName().equals("book")) {
19. book = new Book();
20. } else if (parser.getName().equals("id")){
21. eventType =parser.next();
22. book.setId(Integer.parseInt(parser.getText()));
23. } else if(parser.getName().equals("name")) {
24. eventType =parser.next();
25. book.setName(parser.getText());
26. } else if(parser.getName().equals("price")) {
27. eventType =parser.next();
28. book.setPrice(Float.parseFloat(parser.getText()));
29. }
30. break;
31. case XmlPullParser.END_TAG:
32. if(parser.getName().equals("book")) {
33. books.add(book);
34. book = null; }
35. break; }
36. eventType = parser.next();}
37. return books; }
38. @Override
39. public String serialize(List<Book>books) throws Exception {
40. // XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
41. // XmlSerializer serializer = factory.newSerializer();
42. XmlSerializer serializer =Xml.newSerializer(); //由android.util.Xml创建一个XmlSerializer实例
43. StringWriter writer = newStringWriter();
44. serializer.setOutput(writer); //设置输出方向为writer
45. serializer.startDocument("UTF-8",true);
46. serializer.startTag("","books");
47. for (Book book : books) {
48. serializer.startTag("","book");
49. serializer.attribute("","id", book.getId() + "");
50. serializer.startTag("","name");
51. serializer.text(book.getName());
52. serializer.endTag("","name");
53. serializer.startTag("","price");
54. serializer.text(book.getPrice() +"");
55. serializer.endTag("","price");
56. serializer.endTag("","book");}
57. serializer.endTag("","books");
58. serializer.endDocument();
59. return writer.toString();
60. } }

上面的代码完全实现了DOM、SAX、PULL三种方式对XML文件的解析以及实体类对象序列化为XML文件。虽然它们都能实现这样的功能,但是在性能以及代码量方面却有所不同。

DOM(Document Object Model,简称DOM,中文:文档对象模型):使用DOM方式解析XML时,我们需要读入整个的XML文档,然后在内存中创建DOM树,生成DOM树上的每个Node对象,即所有的文档内容将一次性全部被解析到内存中,因此它对内存消耗是比较大的,尤其在文档比较大的时候。但是它也具有其他方式所不具有的优势,因为在内存中。他的检索和更新效率特别高,可以随机访问任意元素或在任意位置插值,而SAX和PULL方式都不能实现。

SAX(Simple API for XML)模型:相对于DOM方式,SAX方式并不会将整个文档加载到内存,而是从文档的开始往下依次读取,基于事件模型,当某个事件被触发时,才获取相应的XML的部分数据,从而不管XML文件有多大,都只占用了少量的内存空间。但是,SAX是从文档开始执行遍历的。并且只能遍历一次。也就是说我们不能随机的访问XML文件,只能从头到尾的将XML文件遍历一次(当然也可以中间截断遍历)。

PULL方式:它和SAX方式极为相似,都是基于事件模型。PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器。

以上内容几乎全部参考与博客:/article/7553406.html

自己真正操作一遍加深了印象,以前看过多次,一直都记不住,这次记得脑一些了。

上面是你合计的代码全部都可以在Github仓库中下载:

https://github.com/BBigBoy/AndroidBaseTest XMLParser项目。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: