java的XML解析——StAX PULL解析

本文要点是:

StudentPullUtils类,实现的两个方法示例

一个用于将xml文件中的student解析到List<Student>中,

一个用于将List<Student>中的数据序列化到指定的xml文件中。

转载自:https://www.cnblogs.com/dqrcsc/p/4634074.html建议看原文,格式清晰。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

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_TAG:碰到开始节点时触发

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:

复制代码

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<students>

    <student id="000">

        <name>zhangsan22</name>

        <gender>female</gender>

        <age>26</age>

    </student>

    <student id="002">

        <name>lisi</name>

        <gender>male</gender>

        <age>24</age>

    </student>

    <student id="003">

        <name>xiaoqiao</name>

        <gender>female</gender>

        <age>18</age>

    </student>

    <student id="004">

        <name>diaochan</name>

        <gender>female</gender>

        <age>23</age>

    </student>

</students>

复制代码

对应的实体类:Student.java:

复制代码

package cn.csc.bean;

public class Student {

         private String id = null;

         private String name = null;

         private String gender = null;

         private int age = 0;

         public String getId() {

                   return id;

         }

         public void setId(String id) {

                   this.id = id;

         }

         public String getName() {

                   return name;

         }

         public void setName(String name) {

                   this.name = name;

         }

         public String getGender() {

                   return gender;

         }

         public void setGender(String gender) {

                   this.gender = gender;

         }

         public int getAge() {

                   return age;

         }

         public void setAge(int age) {

                   this.age = age;

         }

         public Student(String id, String name, String gender, int age) {

                   super();

                   this.id = id;

                   this.name = name;

                   this.gender = gender;

                   this.age = age;

         }

         public Student() {

                   super();

         }

         public String toString() {

                   return "[id:"+id+",name:"+name+",gender:"+gender+",age"+age+"]";

         }

}

复制代码

 

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

复制代码

public class StudentPullUtils {

         public static List<Student> parseXml(String filename) throws Exception{

                   List<Student> list = new ArrayList<Student>();

                   XmlPullParserFactory factory = XmlPullParserFactory.newInstance();

                   XmlPullParser parser = factory.newPullParser();

                   parser.setInput(new FileInputStream(filename), "utf-8");

                   int eventType;

                   Student s = null;

                   while((eventType = parser.getEventType())!= XmlPullParser.END_DOCUMENT){

                            if(eventType == XmlPullParser.START_TAG && parser.getName().equals("student")){

                                     s = new Student();

                                     s.setId(parser.getAttributeValue(0));

                            }

                            if(eventType == XmlPullParser.START_TAG && parser.getName().equals("name")){

                                     s.setName(parser.nextText());

                            }

                            if(eventType == XmlPullParser.START_TAG && parser.getName().equals("age")){

                                     s.setAge(Integer.parseInt(parser.nextText()));

                            }

                            if(eventType == XmlPullParser.START_TAG && parser.getName().equals("gender")){

                                     s.setGender(parser.nextText());

                            }

                            if(eventType == XmlPullParser.END_TAG && parser.getName().equals("student")){

                                     list.add(s);

                            }

                            parser.next();

                   }

                   return list;

         }

        

         public static boolean serializeList(List<Student> list, String filename) throws Exception{

                   XmlPullParserFactory factory = XmlPullParserFactory.newInstance();

                   XmlSerializer serializer = factory.newSerializer();

                   serializer.setOutput(new FileOutputStream(filename), "utf-8");

                   serializer.startDocument("utf-8", true);

                   serializer.startTag(null, "students");

                   for(Student s : list){

                            serializer.startTag(null, "student");

                            serializer.attribute(null, "id", s.getId());

                            serializer.startTag(null, "name");

                            serializer.text(s.getName());

                            serializer.endTag(null, "name");

                            serializer.startTag(null, "gender");

                            serializer.text(s.getGender());

                            serializer.endTag(null, "gender");

                            serializer.startTag(null, "age");

                            serializer.text(s.getAge()+"");

                            serializer.endTag(null, "age");

                            serializer.endTag(null, "student");

                   }

                   serializer.endTag(null, "students");

                   serializer.endDocument();

                  

                   return true;

         }

}

复制代码

 

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

复制代码

List<Student> list = StudentPullUtils.parseXml("students.xml");

for(Student s: list){

         s.setAge(s.getAge()+1);

}

StudentPullUtils.serializeList(list, "students_bak.xml");

复制代码

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值