解析XML有三种方式:Dom、SAX、Pull
其中pull解析器运行方式与SAX类似。
我们首先认识pull解析器:http://developer.android.com/intl/zh-cn/reference/org/xmlpull/v1/XmlPullParser.html
Th following event types are seen by next()
1.解析
获取解析器: Xml.newPullParser()
设置输入流: parser.setInput(InputStream, String)
获取当前事件类型: parser.getEventType(),
获取下一个事件类型: parser.next()
获取标签名: parser.getName()
获取属性值: parser.getAttributeValue(int)、getAttributeValue(null,"id")
获取下一个文本: parser.nextText()
2.生成
获取解析器:
设置输出流:
开始文档:
结束文档:
开启标签:
结束标签:
设置属性:
设置文本:
下面我们用一个实例来看看:
在src下面新建presons.xml
1 <?xml version='1.0' encoding='UTF-8' standalone='yes' ?> 2 <persons> 3 <person id="1"> 4 <name>范冰冰</name> 5 <age>31</age> 6 </person> 7 <person id="2"> 8 <name>林志玲</name> 9 <age>38</age> 10 </person> 11 <person id="3"> 12 <name>杨幂</name> 13 <age>26</age> 14 </person> 15 </persons>
然后在包中创建Person.java、PersonService.java、PersonTest.java
1 public class PersonService { 2 3 public List<Person> loadPersons(InputStream in) throws Exception { 4 XmlPullParser parser = Xml.newPullParser(); // 获取解析器 5 parser.setInput(in, "UTF-8"); // 设置输入流, 指定码表 6 7 ArrayList<Person> persons = new ArrayList<Person>(); 8 Person p = null; 9 10 // 最初type赋值为第一个事件, 只要不是文档结束就循环, 每次循环后解析下一个事件 11 for (int type = parser.getEventType(); type != XmlPullParser.END_DOCUMENT; type = parser.next()) { 12 if (type == XmlPullParser.START_TAG) { // 如果遇到了标签开始事件 13 if (parser.getName().equals("person")) { // 如果标签名为"person" 14 p = new Person(); // 创建对象 15 String id = parser.getAttributeValue(0); // 获取第一个属性的属性值 16 p.setId(Integer.parseInt(id)); // 转为int, 设置id 17 persons.add(p); // 装入集合 18 } else if (parser.getName().equals("name")) { // 如果标签名为"name" 19 String name = parser.nextText(); // 获取下一个文本 20 p.setName(name); // 设置name 21 } else if (parser.getName().equals("age")) { // 如果标签名为"age" 22 String age = parser.nextText(); // 获取下一个文本 23 p.setAge(Integer.parseInt(age)); // 设置age 24 } 25 } 26 } 27 28 return persons; 29 } 30 31 public void savePersons(List<Person> persons, OutputStream out) throws IOException { 32 XmlSerializer serializer = Xml.newSerializer(); // 获取序列化工具 33 serializer.setOutput(out, "UTF-8"); // 设置输出流, 指定码表 34 35 serializer.startDocument("UTF-8", true); // 开始文档 36 serializer.startTag(null, "persons"); // 开始标签 37 38 for (Person p : persons) { 39 serializer.startTag(null, "person"); 40 serializer.attribute(null, "id", p.getId().toString()); // 设置属性 41 42 serializer.startTag(null, "name"); 43 serializer.text(p.getName()); // 设置文本 44 serializer.endTag(null, "name"); 45 46 serializer.startTag(null, "age"); 47 serializer.text(p.getAge().toString()); 48 serializer.endTag(null, "age"); 49 50 serializer.endTag(null, "person"); 51 } 52 53 serializer.endTag(null, "persons"); // 结束标签 54 serializer.endDocument(); // 结束文档 55 } 56 57 }
1 public class PersonTest extends AndroidTestCase { 2 3 public void testLoad() throws Exception { 4 PersonService service = new PersonService(); 5 InputStream in = PersonTest.class.getClassLoader().getResourceAsStream("persons.xml"); 6 List<Person> persons = service.loadPersons(in); 7 for (Person p : persons) 8 System.out.println(p); 9 10 Person p = new Person(4, "张红", 18); 11 persons.add(p); 12 service.savePersons(persons, new FileOutputStream("/mnt/sdcard/persons.xml")); 13 } 14 15 }
1 public class Person { 2 private Integer id; 3 private String name; 4 private Integer age; 5 6 public Person() { 7 super(); 8 } 9 10 public Person(Integer id, String name, Integer age) { 11 super(); 12 this.id = id; 13 this.name = name; 14 this.age = age; 15 } 16 17 public Integer getId() { 18 return id; 19 } 20 21 public void setId(Integer id) { 22 this.id = id; 23 } 24 25 public String getName() { 26 return name; 27 } 28 29 public void setName(String name) { 30 this.name = name; 31 } 32 33 public Integer getAge() { 34 return age; 35 } 36 37 public void setAge(Integer age) { 38 this.age = age; 39 } 40 41 @Override 42 public String toString() { 43 return "Person [id=" + id + ", name=" + name + ", age=" + age + "]"; 44 } 45 46 }
然后运行程序,可在日志中看到解析的数据。
(最好添加一个日志信息的过滤器,专门查看System.out输出的信息)
以上部分只讲解了PULL解析,下面我们用这三种解析方式解析同一个XML文件(在代码中注释讲解)。
需要我们解析的XML内容如下:
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?> <persons> <person id="1"> <name>saber</name> <age>20</age> </person> <person id="2"> <name>Archer</name> <age>21</age> </person> <person id="3"> <name>Lancer</name> <age>26</age> </person> </persons>
其存放在名为“assets”的文件夹下,取名为“test”。
整个程序代码文件如下:
接下来,实现一个实体类,该类的属性应与XML文件对应,名为“Person.java”,其实现如下:
package com.topcsa.entity; public class Person { private Integer id; private String name; private Integer age; public Person() { super(); } public Person(Integer id, String name, Integer age) { super(); this.id = id; this.name = name; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + ", age=" + age + "]"; } }
名为“XmlUtils.java”的文件实现如下:
package com.topcsa.utils; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import com.topcsa.entity.Person; import android.content.Context; import android.util.Xml; public class XmlUtils { public List<Person> XmlPullParse(Context con) { InputStream inputStream = null; ArrayList<Person> persons = new ArrayList<Person>(); Person p = null; XmlPullParser parser = Xml.newPullParser(); // 获取解析器 // 得到文件流,并设置编码方式 try { inputStream = con.getResources().getAssets().open("test.xml"); parser.setInput(inputStream, "UTF-8"); // 设置输入流, 指定码表 // 最初type赋值为第一个事件, 只要不是文档结束就循环, 每次循环后解析下一个事件 for (int type = parser.getEventType(); type != XmlPullParser.END_DOCUMENT; type = parser .next()) { if (type == XmlPullParser.START_TAG) { // 如果遇到了标签开始事件 if (parser.getName().equals("person")) { // 如果标签名为"person" p = new Person(); // 创建对象 String id = parser.getAttributeValue(0); // 获取第一个属性的属性值 p.setId(Integer.parseInt(id)); // 转为int, 设置id persons.add(p); // 装入集合 } else if (parser.getName().equals("name")) { // 如果标签名为"name" String name = parser.nextText(); // 获取下一个文本 p.setName(name); // 设置name } else if (parser.getName().equals("age")) { // 如果标签名为"age" String age = parser.nextText(); // 获取下一个文本 p.setAge(Integer.parseInt(age)); // 设置age } } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (XmlPullParserException e) { // TODO Auto-generated catch block e.printStackTrace(); } return persons; } public List<Person> XmlSaxParse(Context con) { List<Person> persons = null; // 建立Sax解析工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); try { // 取得SaxParser对象 SAXParser parser = factory.newSAXParser(); // 获取事件源 XMLReader xmlReader = parser.getXMLReader(); // 设置sax解析器 PersonSaxHandler handler = new PersonSaxHandler(); xmlReader.setContentHandler(handler); // 解析xml文档 xmlReader.parse(new InputSource(con.getAssets().open("test.xml"))); persons = handler.getPersons(); } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return persons; } public List<Person> XmlDomParse(Context con) { List<Person> persons = new ArrayList<Person>(); DocumentBuilderFactory factory = null; DocumentBuilder builder = null; Document document = null; InputStream inputStream = null; // 建立DocumentBuilderFactory对象,用于取得DocumentBuilder factory = DocumentBuilderFactory.newInstance(); try { // 找到XML文档 inputStream = con.getResources().getAssets().open("test.xml"); // 通过DocumentBuilderFactory取得DocumentBuilder builder = factory.newDocumentBuilder(); // 读取指定路径的XML文件 document = builder.parse(inputStream); // 找到根Element Element root = document.getDocumentElement(); NodeList nodes = root.getElementsByTagName("person"); // 遍历所有根节点下的子节点,persons下的所有person Person person = null; for (int i = 0; i < nodes.getLength(); i++) { person = new Person(); // 获取person元素节点 Element personElement = (Element) (nodes.item(i)); // 获取person中id属性值 person.setId(Integer.parseInt(personElement.getAttribute("id"))); // 获取person下name标签 Element personName = (Element) personElement .getElementsByTagName("name").item(0); person.setName(personName.getFirstChild().getNodeValue()); // 获取person下age标签 Element personAge = (Element) personElement .getElementsByTagName("age").item(0); person.setAge(Integer.parseInt(personAge.getFirstChild() .getNodeValue())); persons.add(person); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); } return persons; } //Sax解析方式需要的类 class PersonSaxHandler extends DefaultHandler { private List<Person> list = null; private String elementName = null; private Person person = null; @Override public void startDocument() throws SAXException {// 文档开始,实例化集合 // TODO Auto-generated method stub this.list = new ArrayList<Person>(); } // 元素开始 @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { localName = localName.toLowerCase().trim(); // 如果读取的是person标签开始,则实例化Person if (localName.equals("person")) { this.person = new Person(); // 导航到person开始节点后 this.person.setId(Integer.parseInt(attributes.getValue("id"))); } // 保存元素名称 this.elementName = localName; } @Override public void characters(char[] ch, int start, int length)// 获取元素类容 throws SAXException { if (this.elementName != null) {// 表示有元素 String data = new String(ch, start, length);// 取得文字信息 if (this.elementName.equals("name")) { this.person.setName(data); } else if (this.elementName.equals("age")) { this.person.setAge(Integer.parseInt(data)); } } } // 元素结尾 @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (localName.equals("person")) {// 判断元素标记是"person" this.list.add(this.person);// 向集合中保存数据 this.person = null;// 清空对象 } this.elementName = null;// 青空元素标记 } public List<Person> getPersons() {// 取得全部集合 return this.list; } } }
MainActivity的布局文件activity_main.xml实现如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/btn_dom" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Dom解析" /> <Button android:id="@+id/btn_sax" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Sax解析" /> <Button android:id="@+id/btn_pull" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Pull解析" /> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
MainActivity的实现如下:
package com.topcsa.zhj_test; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.support.v4.widget.DrawerLayout; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import com.topcsa.entity.Person; import com.topcsa.utils.XmlUtils; public class MainActivity extends Activity { private XmlUtils xmlutils; private List<Person> persons; private StringBuffer sb; private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btnDom = (Button) findViewById(R.id.btn_dom); Button btnSax = (Button) findViewById(R.id.btn_sax); Button btnPull = (Button) findViewById(R.id.btn_pull); xmlutils = new XmlUtils(); persons = new ArrayList<Person>(); sb = new StringBuffer(); btnDom.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { sb.append("Dom解析:"); persons = xmlutils.XmlDomParse(MainActivity.this); for (int i = 0; i < persons.size(); i++) { Person person = persons.get(i); sb.append("姓名:" + person.getName() + ",id:" + person.getId() + ",年龄:" + person.getAge() + "; "); } tv.setText(sb.toString()); } }); btnSax.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { sb.append("Sax解析:"); persons = xmlutils.XmlSaxParse(MainActivity.this); for (int i = 0; i < persons.size(); i++) { Person person = persons.get(i); sb.append("姓名:" + person.getName() + ",id:" + person.getId() + ",年龄:" + person.getAge() + "; "); } tv.setText(sb.toString()); } }); btnPull.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { sb.append("Pull解析:"); persons = xmlutils.XmlPullParse(MainActivity.this); if (persons != null) { System.out.println("不为空"+persons.size()); } else { System.out.println("为空"); } for (int i = 0; i < persons.size(); i++) { Person person = persons.get(i); sb.append("姓名:" + person.getName() + ",id:" + person.getId() + ",年龄:" + person.getAge() + "; "); } tv.setText(sb.toString()); } }); tv = (TextView) findViewById(R.id.tv); } }
最后程序运行如下: