• java拾遗3----XML解析(三) StAX PULL解析


    使用PULL方式解析XML:

    Pull是STAX的一个实现

    StAX是The Streaming API for XML的缩写,一种利用拉模式解析(pull-parsing)XML文档的API

    StAX通过提供一种基于事件迭代器(Iterator)的API让程序员去控制xml文档解析过程。

    为什么说StAX方式的效率优于SAX呢?

    因为SAX 是推模式的,所有的操作在解析器自动控制下进行,所有事件都会处理,不管需不需要解析整个文档,解析器都会自动启动解析任务,然后按顺序向下解析,直到解析完成才终止。而StAX 是拉模式的,可以由用户根据需要控制需要处理事件类型及何时终止解析任务,用户调用一次next(),解析器就进行一次向下解析,完全在用户的控制下进行解析操作,在需要的解析工作已经完成时,可以随时终止解析。

    简单说来,推模式,就是你把如何操作通通告诉解析器,之后,解析器自动去完成所有解析任务,你不能做任何干涉了。

    而拉模式就像抽纸,随用随拉,需要时就拉一下,不需要时,它不会自动推出来。你可以一直拉把一盒抽纸拉完,也可以按自己需要只拉几张。

    可以从网上下载PULL解析的第三方jar包,来使用PULL解析XML

    www.xmlpull.org上有3种PULL的实现可以下载:

     

    由描述信息可以看出,XPP3这种实现主要致力于性能和易于使用,而且,android内置的PULL解析器似乎也是XPP3,所以可以下载这种实现,来实现XML的PULL解析。

    选择合适的XPP3下载:

     

    如,我下载了:

     

    下载完成后,解压缩,然后找到文件名类似于xpp3-1.1.4c.jar的jar包,这里面就有我们需要的API。

    doc目录中的api目录中存放着API帮助手册,可以参考该手册,学习使用XPP3 PULL解析器。

     

    如同DOM和SAX解析XML一样,PULL解析XML也要用到解析器工厂类XmlPullParserFactory,解析器类XmlPullParser,XPP3中还提供了XmlSerializer类用于将内存对象实现序列化到xml文档。

     

    工厂类也是通过静态方法newInstance()获得工厂类对象。

     

    newPullParser()和newSerializer()方法分别用于获取XmlPullParser对象和XmlSerializer对象。

    以上就是工厂类的常用的三个方法。

    XmlPulParser通过setInput()方法,设置要解析的XML文档。

     

    通过调用next方法,一步步向下解析

     

    通过调用getEventType()方法,来确认当前解析XML所触发的事件类型。

    事件类型通过XmlPullParser中定义的几个常量来标识:

    START_DOCUMENT:开始解析触发

    START_DOCUMENT:碰到节点时触发

    TEXT:读取字符文本时触发

    END_TAG:碰到结束节点时触发

    END_DOCUMENT:解析完成时触发

    当触发事件类型是START_TAG或者END_TAG时,可以通过getName()方法获取当前节点名称。

     

    当事件类型是START_TAG时,可以通过nextText()获取该节点的文本子节点内容,若事件类型为END_TAG则会返回一个空字符串。

     

    当事件类型是START_TAG时,通过getAttributeCount()方法,可以获取该节点的属性个数

    通过getAttributeName(int index)方法,可以获取指定index的属性的名称

     

    通过getAttributeValue(int index)方法,可以获取指定index属性的值。

    以上,是XmlPullParser类中的几个常用方法。

    XmlSerializer实现将内存中的数据序列化到XML文档中,也有几个常用的方法:

    setOutput()方法,指定要将数据序列化到哪个XML文件中

     

    startDocument()方法,指定XML文档的开始<?xml声明信息

    如:startDocument(“utf-8”, true);将在XML文档中输出如下信息:

    <?xml encoding="UTF-8" standalone="yes"?>

    startTag()开始一个节点,namespace没有,一般设置为null或者空字符串

     

    text()设置文本内容

     

    endTage()结束一个节点。

     

    attribute()设置节点的属性。

     

    了解了这几个类的常用方法后,就可以实现PULL模式的XML解析和序列化了。但是,现在有个问题:DOM可以实现增删改查操作,PULL模式可以吗?

    由于在DOM模式下,整个文档对象都在内存中,所以可以实现修改回写。但是PULL模式以及SAX模式下,都是边解析边释放内存的,不能直接实现增删改查操作。但是,可以模仿DOM模式,把解析的部分保存在内存中,如把解析的对象都保存到一个List中。然后所有的增删改查操作,都针对List对象进行,所有操作执行完成之后,再把内存中最终版本的List序列化到Xml文档中,就间接实现了PULL模式下的增删改查操作。

    具体操作可以参考下面代码:

    待解析的students.xml:

     1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
     2 
     3 <students>
     4 
     5     <student id="000">
     6 
     7         <name>zhangsan22</name>
     8 
     9         <gender>female</gender>
    10 
    11         <age>26</age>
    12 
    13     </student>
    14 
    15     <student id="002">
    16 
    17         <name>lisi</name>
    18 
    19         <gender>male</gender>
    20 
    21         <age>24</age>
    22 
    23     </student>
    24 
    25     <student id="003">
    26 
    27         <name>xiaoqiao</name>
    28 
    29         <gender>female</gender>
    30 
    31         <age>18</age>
    32 
    33     </student>
    34 
    35     <student id="004">
    36 
    37         <name>diaochan</name>
    38 
    39         <gender>female</gender>
    40 
    41         <age>23</age>
    42 
    43     </student>
    44 
    45 </students>

    对应的实体类:Student.java:

     1 package cn.csc.bean;
     2 
     3 public class Student {
     4 
     5          private String id = null;
     6 
     7          private String name = null;
     8 
     9          private String gender = null;
    10 
    11          private int age = 0;
    12 
    13          public String getId() {
    14 
    15                    return id;
    16 
    17          }
    18 
    19          public void setId(String id) {
    20 
    21                    this.id = id;
    22 
    23          }
    24 
    25          public String getName() {
    26 
    27                    return name;
    28 
    29          }
    30 
    31          public void setName(String name) {
    32 
    33                    this.name = name;
    34 
    35          }
    36 
    37          public String getGender() {
    38 
    39                    return gender;
    40 
    41          }
    42 
    43          public void setGender(String gender) {
    44 
    45                    this.gender = gender;
    46 
    47          }
    48 
    49          public int getAge() {
    50 
    51                    return age;
    52 
    53          }
    54 
    55          public void setAge(int age) {
    56 
    57                    this.age = age;
    58 
    59          }
    60 
    61          public Student(String id, String name, String gender, int age) {
    62 
    63                    super();
    64 
    65                    this.id = id;
    66 
    67                    this.name = name;
    68 
    69                    this.gender = gender;
    70 
    71                    this.age = age;
    72 
    73          }
    74 
    75          public Student() {
    76 
    77                    super();
    78 
    79          }
    80 
    81          public String toString() {
    82 
    83                    return "[id:"+id+",name:"+name+",gender:"+gender+",age"+age+"]";
    84 
    85          }
    86 
    87 }

    StudentPullUtils类,实现两个方法,一个用于将xml文件中的student解析到List<Student>中,一个用于将List<Student>中的数据序列化到指定的xml文件中:

      1 public class StudentPullUtils {
      2 
      3          public static List<Student> parseXml(String filename) throws Exception{
      4 
      5                    List<Student> list = new ArrayList<Student>();
      6 
      7                    XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
      8 
      9                    XmlPullParser parser = factory.newPullParser();
     10 
     11                    parser.setInput(new FileInputStream(filename), "utf-8");
     12 
     13                    int eventType;
     14 
     15                    Student s = null;
     16 
     17                    while((eventType = parser.getEventType())!= XmlPullParser.END_DOCUMENT){
     18 
     19                             if(eventType == XmlPullParser.START_TAG && parser.getName().equals("student")){
     20 
     21                                      s = new Student();
     22 
     23                                      s.setId(parser.getAttributeValue(0));
     24 
     25                             }
     26 
     27                             if(eventType == XmlPullParser.START_TAG && parser.getName().equals("name")){
     28 
     29                                      s.setName(parser.nextText());
     30 
     31                             }
     32 
     33                             if(eventType == XmlPullParser.START_TAG && parser.getName().equals("age")){
     34 
     35                                      s.setAge(Integer.parseInt(parser.nextText()));
     36 
     37                             }
     38 
     39                             if(eventType == XmlPullParser.START_TAG && parser.getName().equals("gender")){
     40 
     41                                      s.setGender(parser.nextText());
     42 
     43                             }
     44 
     45                             if(eventType == XmlPullParser.END_TAG && parser.getName().equals("student")){
     46 
     47                                      list.add(s);
     48 
     49                             }
     50 
     51                             parser.next();
     52 
     53                    }
     54 
     55                    return list;
     56 
     57          }
     58 
     59         
     60 
     61          public static boolean serializeList(List<Student> list, String filename) throws Exception{
     62 
     63                    XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
     64 
     65                    XmlSerializer serializer = factory.newSerializer();
     66 
     67                    serializer.setOutput(new FileOutputStream(filename), "utf-8");
     68 
     69                    serializer.startDocument("utf-8", true);
     70 
     71                    serializer.startTag(null, "students");
     72 
     73                    for(Student s : list){
     74 
     75                             serializer.startTag(null, "student");
     76 
     77                             serializer.attribute(null, "id", s.getId());
     78 
     79                             serializer.startTag(null, "name");
     80 
     81                             serializer.text(s.getName());
     82 
     83                             serializer.endTag(null, "name");
     84 
     85                             serializer.startTag(null, "gender");
     86 
     87                             serializer.text(s.getGender());
     88 
     89                             serializer.endTag(null, "gender");
     90 
     91                             serializer.startTag(null, "age");
     92 
     93                             serializer.text(s.getAge()+"");
     94 
     95                             serializer.endTag(null, "age");
     96 
     97                             serializer.endTag(null, "student");
     98 
     99                    }
    100 
    101                    serializer.endTag(null, "students");
    102 
    103                    serializer.endDocument();
    104 
    105                   
    106 
    107                    return true;
    108 
    109          }
    110 
    111 }

    调用测试:实现将数据从students.xml中读取到Lis<Student>中,所有学生的年龄加1,然后序列化到students_bak.xml中:

    1 List<Student> list = StudentPullUtils.parseXml("students.xml");
    2 
    3 for(Student s: list){
    4 
    5          s.setAge(s.getAge()+1);
    6 
    7 }
    8 
    9 StudentPullUtils.serializeList(list, "students_bak.xml");
  • 相关阅读:
    值类型和引用类型
    0513二分查找练习
    0512随机4位验证码
    0511java 随机6个不同的彩票数
    随机数的产生机制
    0510Java 练习
    0509java练习题
    java循环作业
    字符集的由来及发展
    hdu2577_键入字母
  • 原文地址:https://www.cnblogs.com/dqrcsc/p/4634074.html
Copyright © 2020-2023  润新知