DOM解析XML文件时,会将XML文件的所有内容以文档树方式存放在内存中,然后允许您使用DOM API遍历XML树、检索所需的数据。使用DOM操作XML的代码看起来是比较直观的,并且在某些方面比基于SAX的实现更加简单。但是,因为DOM需要 将XML文件的所有内容以文档树方式存放在内存中,所以内存的消耗比较大,特别对于运行Android的移动设备来说,因为设备的资源比较宝贵,所以建议还是采用SAX来解析XML文件,当然,如果XML文件的内容比较小采用DOM也是可行的
DOM解析虽然我们在android中并不推荐使用,但是这并不代表着不可以实现。dom的原理是把xml文件的各种部分都看成是节点,所有的节点因为层级关系最后形成了一颗节点树。而DOM的解析方式便是在内存中生存这棵树,并允许用户进行相关的操作。
定义一个XML
public classDOMPersonService {
public static List<Person>getPersonList(InputStream inStream) throws Exception{
List<Person> personList =new ArrayList();
DocumentBuilderFactory factory =DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document =builder.parse(inStream);
//注意,此时xml文件已经都被装入内存中的document对象里了
//取得根结点(元素节点)
Element root =document.getDocumentElement();
NodeList nodes =root.getElementsByTagName("person");
for(int i=0;i<nodes.getLength(); i++){
Element personElement =(Element) nodes.item(i);
Person person = newPerson();
//为person添加id属性值
person.setId(Integer.valueOf(personElement.getAttribute("id")));
NodeList childNodes =personElement.getChildNodes();
//遍历孩子节点,忽略文本节点,保留并处理元素节点
for(int j=0;j<childNodes.getLength(); j++){
Node childNode =childNodes.item(j);
if(childNode.getNodeType()== Node.ELEMENT_NODE){
if("name".equals(childNode.getNodeName())){
person.setName(childNode.getFirstChild().getNodeValue());
}elseif("age".equals(childNode.getNodeName())){
TexttextNode = (Text) childNode.getFirstChild();
StringageStr = textNode.getNodeValue();
person.setAge(Integer.valueOf(ageStr));
}
}
}
personList.add(person);
}
return personList;
}
}
<?xmlversion="1.0" encoding="UTF-8"?>
<persons>
<person id="111">
<name>Tom</name>
<age>20</age>
</person>
<person id="222">
<name>Mary</name>
<age>17</age>
</person>
</persons>
这里列出几个dom中经常用到的方法
Node 接口的常用方法
一个节点可以调用
shortgetNodeType()
方法返回一个表示节点类型的常量(Node接口规定的常量值),例如,对于Element节点,getNodeType()方法返回的值为:
Node.ELEMENT_NODE
节点可以调用
NodeList getChildNodes()
返回一个由当前节点的所有子节点组成的NodeList对象。节点调用
Node getFirstChild()
返回当前节点的第一个子节点。节点调用
Node getLastChild()
返回当前节点的最后一个子节点。节点可以调用
NodeList getTextContent()
返回当前节点及所有子孙节点中的文本内容。
SAX是一种XML解析的替代方法。相比于DOM,SAX是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一 边解析。而且相比于DOM,SAX可以在解析文档的任意时刻停止解析,但任何事物都有其相反的一面,对于SAX来说就是操作复杂
DOM和SAX的解析方式不相同,DOM方式先扫描xml文件并生成树结构,树结构存储在内存里,操作便利。而SAX解析则由消息响应驱动,不需将文档调入内存。
事件处理的顺序,处理时间的位置:一般在startDocument()初始化工作,在endDocument()中收尾的处理工 作;startElement()—characters()—endDocument()是一个XML节点读取的过程,startElement()用 来初始判断,characters()获取节点的字符数据,endDocument()将数据写入数据结构。
public classSAXPersonService {
public List<Person>getPersonList(InputStream inStream) throws Exception{
//得到创建SAX解析器的工厂对象
SAXParserFactory factory =SAXParserFactory.newInstance();
//让工厂对象创建解析器对象
SAXParser parser =factory.newSAXParser();
//创建DefaultHandler对象
PersonHandler handler = newPersonHandler();
//使用parser的parser(Inputstream in, DefaultHandler handler)进行解析
parser.parse(inStream, handler);
List<Person> personList =handler.getPersonlist();
return personList;
}
}
覆盖defaulthandler几个方法
public classPersonHandler extends DefaultHandler {
List<Person> personList = null;
Person person = null;
String elementTag = null;
public void startDocument() throwsSAXException {
personList = newArrayList<Person>();
}
public void startElement(String uri,String localName, String qName,
Attributes attributes)throws SAXException {
if("person".equals(localName)) {
person = new Person();
String id =attributes.getValue(0);
person.setId(Integer.valueOf(id));
}
elementTag = localName;
}
public void characters(char[] ch, intstart, int length)
throws SAXException {
String data = new String(ch, start,length);
if (elementTag != null &&person !=null) {
if("name".equals(elementTag)) {
person.setName(data);
} else if("age".equals(elementTag)) {
person.setAge(Integer.valueOf(data));
}
}
}
public void endElement(String uri, StringlocalName, String qName)
throws SAXException {
if("person".equals(localName)) {
personList.add(person);
person = null;
}
elementTag = null;
}
public void endDocument() throwsSAXException {
}
public List<Person> getPersonlist(){
return personList;
}
}
startDocument:当遇到文档的时候就触发这个事件 调用这个方法 可以在其中做些预处理工作。
startElement:(String namespaceURI,String localName,String qName,Attributes atts)当遇开始标签的时候就会触发这个方法。
endElement(String uri,String localName,String name):当遇到结束标签时触发这个事件,调用此法可以做些善后工作。
charachers(char []ch,int start,int length):当遇到xml内容时触发这个方法,用newString(ch,start,length)可以接受内容。
PULL
除了可以使用 SAX和DOM解析XML文件,大家也可以使用Android内置的Pull解析器解析XML文件。 Pull解析器的运行方式与SAX 解析器相似。它提供了类似的事件,如:开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。事件将作为数值代码被发送,因此可以使用一个switch对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法可以获取下一个Text类型节点的值。
1.常见的XML解析方式有三种,DOM、SAX、Pull,Android系统中推荐使用Pull
2.Pull解析器是一个开源的Java项目,Android系统内部解析XML文件均为此种方式,也可用于JavaEE项目
3.Android SDK中已经集成了Pull解析器,无需添加任何jar文件
4.Pull解析器运行方式与SAX类似,提供各种事件的判断
使用Pull解析器解析XML文件
1. Xml.newPullParser() 获得解析器
2 parser.setInput(in, "UTF-8") 设置输入流以及编码
3. parser.next() 获取下一个解析事件,得到一个事件代码
4. XmlPullParser中定义了常量来标识各种解析事件
START_DOCUMENT、END_DOCUMENT 、START_TAG 、END_TAG 、TEXT
建议使用次解析方式
public classPullPersonService {
public static List<Person>getPersonList(InputStream inStream)
throws Exception {
List<Person> personList =null;
XmlPullParser parser =Xml.newPullParser();
parser.setInput(inStream,"utf-8");
int eventType =parser.getEventType();
Person person = null;
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
caseXmlPullParser.START_DOCUMENT: //判断当前事件是否是文档开始事件
personList = newArrayList<Person>();
break;
caseXmlPullParser.START_TAG:
// 判断当前元素名是否为person
if("person".equals(parser.getName())) {
person = newPerson();
person.setId(Integer.valueOf(parser.getAttributeValue(0)));
} else if("name".equals(parser.getName())) {
person.setName(parser.nextText());
} else if("age".equals(parser.getName())) {
person.setAge(Integer.valueOf(parser.nextText()));
}
break;
case XmlPullParser.END_TAG://判断当前事件是否是标签元素结束事件
if("person".equals(parser.getName()) && person != null) { //判断结束标签元素是否是person
personList.add(person);
person= null;
}
break;
}
// next方法的调用导致下一个节点的解析,同时返回下一个节点解析的事件类型代码
eventType = parser.next();
}
return personList;
}
利用PULL//创建XML文件
public static voidwritePersonList(List<Person> personList, Writer writer)
throws Exception {
XmlSerializer serializer =Xml.newSerializer();
serializer.setOutput(writer);
// 相当于写入<?xmlversion="1.0" encoding="UTF-8"?>
serializer.startDocument("utf-8",true);
//写入跟元素的起始标签
serializer.startTag(null,"persons");
//遍历personList,并且将集合中的Person对象作为person节点写入xml
for(Person person: personList){
serializer.startTag(null,"person");
//为person元素添加id属性
serializer.attribute(null,"id", String.valueOf(person.getId()));
serializer.startTag(null,"name");
serializer.text(person.getName());
serializer.endTag(null,"name");
serializer.startTag(null,"age");
serializer.text(String.valueOf(person.getAge()));
serializer.endTag(null,"age");
serializer.endTag(null,"person");
}
//写入跟元素的结束标签
serializer.endTag(null,"persons");
//结束文档的写入
serializer.endDocument();
writer.flush();
writer.close();
}
测试方法
public class Testextends AndroidTestCase {
public void testSAX() throws Throwable {
List<Person> personList =null;
SAXPersonService service = newSAXPersonService();
InputStream inStream =this.getClass().getClassLoader()
.getResourceAsStream("person_list.xml");
personList =service.getPersonList(inStream);
// for(int i=0;i<personList.size(); i++){
// Log.i("TAG", personList.get(i).toString());
// }
Log.i("TAG",personList.toString());
}
public void testDOM() throws Throwable {
List<Person> personList =null;
InputStream inStream =this.getClass().getClassLoader()
.getResourceAsStream("person_list.xml");
personList =DOMPersonService.getPersonList(inStream);
Log.i("TAG",personList.toString());
}
public void testPull() throws Throwable {
InputStream inStream =this.getClass().getClassLoader()
.getResourceAsStream("person_list.xml");
List<Person> personList =PullPersonService.getPersonList(inStream);
Log.i("TAG",personList.toString());
}
public void testPullSave() throwsThrowable{
List<Person> personList =new ArrayList<Person>();
personList.add(newPerson(999,"Tom", 20));
personList.add(newPerson(888,"Mary", 21));
personList.add(newPerson(777,"Jack", 10));
File file = newFile(this.getContext().getFilesDir(), "new_persons.xml");
Writer writer = newFileWriter(file);
PullPersonService.writePersonList(personList,writer);
}