Android解析XML文件的三方法

来源:互联网 发布:nodejs 连接数据库 编辑:程序博客网 时间:2024/05/22 00:05


PULL

除了可以使用 SAX和DOM解析XML文件,大家也可以使用Android内置的Pull解析器解析XML文件。 Pull解析器的运行方式与 SAX 解析器相似。它提供了类似的事件,如:开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。事件将作为数值代码被发送,因此可以使用一个switch对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法可以获取下一个Text类型节点的值。

public class PullService {
public static List<Person> readXML(InputStream inputStream) throws IOException{
    XmlPullParser parser = Xml.newPullParser();
    try {
    parser.setInput(inputStream, "UTF-8");
    int eventType = parser.getEventType();
   
    Person currentPerson = null;
    List<Person> persons = null;
    while (eventType != XmlPullParser.END_DOCUMENT) {
     switch (eventType) {
    case XmlPullParser.START_DOCUMENT://文档开始事件,可以进行数据初始化处理
      persons = new ArrayList<Person>();
      break;
    case XmlPullParser.START_TAG://开始元素事件
      String name = parser.getName();
      if (name.equalsIgnoreCase("person")) {
       currentPerson = new Person();
       currentPerson.setId(new Integer(parser.getAttributeValue(null, "id")));
      } else if (currentPerson != null) {
       if (name.equalsIgnoreCase("name")) {
        currentPerson.setName(parser.nextText());// 如果后面是Text节点,即返回它的值
       } else if (name.equalsIgnoreCase("age")) {
        currentPerson.setAge(new Short(parser.nextText()));
       }
      }
      break;
    case XmlPullParser.END_TAG://结束元素事件
      if (parser.getName().equalsIgnoreCase("person") && currentPerson != null) {
       persons.add(currentPerson);
       currentPerson = null;
      }
      break;
     }
     eventType = parser.next();
    }
    inputStream.close();
    return persons;
    } catch (Exception e) {
     e.printStackTrace();
    }
    return null;
   }

//将内容保存至XML文件
public static String writeXML(List<Person> persons, Writer writer){
     XmlSerializer serializer = Xml.newSerializer();
     try {
         serializer.setOutput(writer);
         serializer.startDocument("UTF-8", true);
       //第一个参数为命名空间,如果不使用命名空间,可以设置为null
         serializer.startTag("", "persons");
         for (Person person : persons){
             serializer.startTag("", "person");
             serializer.attribute("", "id", person.getId().toString());
             serializer.startTag("", "name");
             serializer.text(person.getName());
             serializer.endTag("", "name");
             serializer.startTag("", "age");
             serializer.text(person.getAge().toString());
             serializer.endTag("", "age");
             serializer.endTag("", "person");
         }
         serializer.endTag("", "persons");
         serializer.endDocument();
         return writer.toString();
     } catch (Exception e) {
         e.printStackTrace();
     }
     return null;
}


}

生成的person.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<persons>
<person id="23">
   <name>liming</name>
   <age>30</age>
</person>
<person id="20">
   <name>lili</name>
   <age>25</age>
</person>
</persons>


DOM解析XML文件

DOM解析XML文件时,会将XML文件的所有内容以文档树方式存放在内存中,然后允许您使用DOM API遍历XML树、检索所需的数据。使用DOM操作XML的代码看起来是比较直观的,并且在某些方面比基于SAX的实现更加简单。但是,因为DOM需要将XML文件的所有内容以文档树方式存放在内存中,所以内存的消耗比较大,特别对于运行Android的移动设备来说,因为设备的资源比较宝贵,所以建议还是采用SAX来解析XML文件,当然,如果XML文件的内容比较小采用DOM也是可行的。

public class DOMXmlReader {
public static List<Person> XMLReader(InputStream inStream)throws Exception{
   List<Person> persons=new ArrayList<Person>();
   DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
   try{
    DocumentBuilder builder=factory.newDocumentBuilder();
    Document document= builder.parse(inStream);
    Element root=document.getDocumentElement();
    NodeList items=root.getElementsByTagName("person");//得到所有person节点
    for(int i=0;i<items.getLength();i++){
     Person person=new Person();
     Element personNode=(Element)items.item(i);
     person.setId(new Integer(personNode.getAttribute("id")));
      //获取person节点下的所有子节点(标签之间的空白节点和name/age元素)
     NodeList childsNodes = personNode.getChildNodes();
      for (int j = 0; j < childsNodes.getLength(); j++) {
      Node node = (Node) childsNodes.item(j);    //判断是否为元素类型
      if(node.getNodeType() == Node.ELEMENT_NODE){        
      Element childNode = (Element) node;
                                          //判断是否name元素
         if ("name".equals(childNode.getNodeName())) {
          //获取name元素下Text节点,然后从Text节点获取数据             person.setName(childNode.getFirstChild().getNodeValue());
         } else if ("age".equals(childNode.getNodeName())) {
      person.setAge(new Short(childNode.getFirstChild().getNodeValue()));
         }
      }
            }
        persons.add(person);
     }
     inStream.close();

     
    
    
    
   }catch(Exception e){
    e.printStackTrace();
    
   }
  
  
   return persons;
  
}

}


SAX

SAX是一种占用内存少且解析速度快的解析器,它采用的是事件启动,它不需要解析完整个文档,而是按照内容顺序 看文档某个部分是否符合xml语法,如果符合就触发相应的事件,所谓的事件就是些回调方法(callback),这些方法 定义在ContentHandler中,下面是其主要方法:

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内容时触发这个方法,用new String(ch,start,length)可以接受内容。

下面是一个例子:

文件名称:person.xml

<?xml version="1.0" encoding="UTF-8"?> <persons> <person id="23"> <name>李明</name> <age>30</age> </person> <person id="20"> <name>李向梅</name> <age>25</age> </person> </persons> 
public class SAXService {


public List<Person> personService(InputStream inStream)throws Exception{
   SAXParserFactory factory=SAXParserFactory.newInstance();
   SAXParser parser=factory.newSAXParser();
   PersonDefaultHandler handler=new PersonDefaultHandler();
   parser.parse(inStream, handler);
   inStream.close();
   return handler.getPersons();
}
private final class PersonDefaultHandler extends DefaultHandler{
   private List<Person> persons=null;
   private Person currentPerson;
   public List<Person> getPersons() {
    return persons;
   }
   public void setPersons(List<Person> persons) {
    this.persons = persons;
   }
   private String tagName=null;

   @Override
   public void characters(char[] ch, int start, int length)
     throws SAXException {
    if(tagName!=null){
     String data =new String(ch,start,length);
     if("name".equals(data)){
      currentPerson.setName(data);
     
     }else if("age".equals(data)){
      currentPerson.setAge(Short.parseShort(data));
     
     }
    
    }
   }

   @Override
   public void endElement(String uri, String localName, String qName)
     throws SAXException {
    if("person".equals(localName)){
    
     persons.add(currentPerson);
     currentPerson=null;
    
    }
    tagName=null;
   
   }

   @Override
   public void startDocument() throws SAXException {
    persons=new ArrayList<Person>();
   }

   @Override
   public void startElement(String uri, String localName, String qName,
     Attributes attr) throws SAXException {
    if("person".equals(localName)){
     currentPerson=new Person();
     currentPerson.setId(Integer.parseInt(attr.getValue("id")));
     
    }
    tagName=localName;
   }
  
}
}
下面是测试类:

public class PersonTest extends AndroidTestCase {
private static final String TAG="PersonTest";
public void testSAXService()throws Throwable{
   SAXService saxservice=new SAXService();
   InputStream inStream=this.getClass().getClassLoader().getResourceAsStream("person.xml");
   List <Person> persons=saxservice.personService(inStream);
   for(Person p:persons){
    Log.i(TAG,p.toString());
   }
}

}


Android系统中XML解析方案的选择

DOM解析器是通过将XML文档解析成树状模型并将其放入内存来完成解析工作的,而后对文档的操作都是在这个树状模型上完成的。这个在内存中的文档树将是文档实际大小的几倍。这样做的好处是结构清除、操作方便,而带来的麻烦就是极其耗费系统资源。而SAX正好克服了DOM的缺点,分析能够立即开始,而不是等待所有的数据被处理。而且,由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中,这对于大型文档来说是个巨大的优点。事实上,应用程序甚至不必解析整个文档;它可以在某个条件得到满足时停止解析。

选择 DOM 还是选择 SAX,这取决于下面几个因素:
应用程序的目的:如果打算对数据作出更改并将它输出为 XML,那么在大多数情况下,DOM 是适当的选择。并不是说使用 SAX 就不能更改数据,但是该过程要复杂得多,因为您必须对数据的一份拷贝而不是对数据本身作出更改。
数据容量: 对于大型文件,SAX 是更好的选择。
数据将如何使用:如果只有数据中的少量部分会被使用,那么使用 SAX 来将该部分数据提取到应用程序中可能更好。 另一方面,如果您知道自己以后会回头引用已处理过的大量信息,那么 SAX 也许不是恰当的选择。
对速度的需要: SAX 实现通常要比 DOM 实现更快。

基于上面的分析,在基于Android系统的内存和CPU资源比较有限的手持设备上,只要我们不需要修改XML数据或者随机的访问XML数据,SAX尽管可能需要更多的编码工作,但是为了更小的内存和CPU消耗,还是值得的。

另外,Android SDK中已经包含了JAXP对应的javax.xml.parsers包,和SAX对应org.xml.sax(当然DOM对应的org.w3c.dom包也包含在内),加上Android还提供了android.sax这样的包来方便SAX Handle的开发,基于JAXP和SAX这样的标准方法来开发不仅复杂度不高,即使出现问题在讨论组中寻求解决方案也是比较容易的。


更多:http://blog.csdn.net/Android_Tutor/article/details/5890835;

http://littlefermat.blog.163.com/blog/static/59771167200981853037951/

0 0
原创粉丝点击