您的位置:首页 > 移动开发 > Android开发

Android解析XML文件的三方法

2015-11-12 17:55 555 查看



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/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  xml