【文件处理】xml 文件 SAX解析

SAX的全称是Simple APIs for XML,也即XML简单应用程序接口。

与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式。

当使用SAX分析器对XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问,因而SAX接口也被称作事件驱动接口

  局限性:

  1. SAX分析器在对XML文档进行分析时,触发了一系列的事件,由于事件触发本身是有时序性的,因此,SAX提供的是一种顺序访问机制,对于已经分析过的部分,不能再倒回去重新处理。

  即,一旦经过了某个元素,我们没有办法返回去再去访问它。

  2. SAX分析器只做了一些简单的工作,大部分工作还要由应用程序自己去做。

  也就是说,SAX分析器在实现时,只是顺序地检查XML文档中的字节流,判断当前字节是XML语法中的哪一部分、是否符合XML语法,然后再触发相应的事件,而事件处理函数本身则要由应用程序自己来实现。

  同DOM分析器相比,SAX分析器缺乏灵活性。

  优势:

  然而,由于SAX分析器实现简单,对内存要求比较低,(SAX不必将整个XML文档加载到内存当中,因此它占据内存要比DOM小), 因此实现效率比较高。

  对于大型的XML文档来说,通常会用SAX而不是DOM。

  并且对于那些只需要访问XML文档中的数据而不对文档进行更改的应用程序来说,SAX分析器更为合适。

SAX分析器

  XML解析器实际上就是一段代码,它读入一个XML文档并分析其结构。

  分类:

  带校验的解析器

  不校验的解析器(效率高)

  支持DOM的解析器(W3C的官方标准)

  支持SAX的解析器(事实上的工业标准)

  SAX是事件驱动的,文档的读入过程就是SAX的解析过程。

  在读入的过程中,遇到不同的项目,解析器会调用不同的处理方法。

【XML文件内容】

<?xml version = "1.0" encoding = "UTF-8"?>
<students>
	<student id="1">
		<name>tonyliu</name>
		<age>19</age>
		<sex>男</sex>
		<group>
			<id>1</id>
			<name>Group1</name>
		</group>
	</student>
	<student id="2">
		<name>Susywang</name>
		<age>18</age>
		<sex>女</sex>
		<group>
			<id>2</id>
			<name>Group2</name>
		</group>
	</student>

	<student id="3">
		<name>JackZhang</name>
		<age>35</age>
		<sex>男</sex>
		<group>
			<id>3</id>
			<name>Group3</name>
		</group>
	</student>
</students>

【SAX 解析代码】

根据xml文件内容分为2个类,一个是Student类另一个为Group类,分别记入相对应的字段。

再定义一个枚举,分别存入一些常量,方便调用。这里要注意的是,仔细看一下xml内容,会发现Student以及group类中都包含了id跟name的字段。所以当我们在写代码中为了让计算机清楚的知道我们指的name,id到底是Student中的还是Group中的,要通过Enum定义的常量来区分。

package Entity;

public class Student {

    private int id;
    private String name;
    private int age;
    private String sex;
    private Group group;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public Group getGroup() {
        return group;
    }
    public void setGroup(Group group) {
        this.group = group;
    }
    public Student(int id, String name, int age, String sex, Group group) {
        super();
        this.id = id;
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.group = group;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    @Override
    public String toString() {
        return "Student [age=" + age + ", group=" + group + ", id=" + id
                + ", name=" + name + ", sex=" + sex + "]";
    }

}

Student 类

package Entity;

public class Group {

    private int id;
    private String name;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Group() {
        super();
        // TODO Auto-generated constructor stub
    }
    public Group(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }
    @Override
    public String toString() {
        return "Group [id=" + id + ", name=" + name + "]";
    }

}

Group 类

package Tool;

public enum StudentEnum {

    stuName,age,sex,groupId,groupName,none

}

Enum(枚举)

package Tool;

import java.util.ArrayList;
import java.util.List;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import Entity.Group;
import Entity.Student;

//继承DefaultHandler这个类,为了使用startDocument,startElement,charecter,endelement,enddocument方法

public class StudentParser extends DefaultHandler{

    private List<Student> students = null;  //创建一个集合方便存放数据
    private boolean isgroupState = false;   //定义标签区分group以及student中的id,name这样的相同字段。因为只有2个类因此boolean类型即可
    private StudentEnum state = StudentEnum.none;  //把枚举的状态设置为none
    private Group group = null;  //初始化Group类
    private Student student = null; //初始化Student类

    //设定一个集合方法为了方便外层调用students这个集合中的内容
    public List<Student> getResult(){
        return this.students;
    }

    @Override
    public void startDocument() throws SAXException {
        students = new ArrayList<Student>();  //初始化集合
    }
    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attrs) throws SAXException {
                //通过startElement方法中的qName来指定xml内容中的student字段
        if(qName.equals("student")){
            String stuId = attrs.getValue("id");  //<Student>的属性只有一个id,因此通过attrs.getValue这个方法获取到id属性
            student = new Student();  //很重要,很重要,很重要。这里一定要初始化Student这个类,为了就是下面通过.setId方法来指定id值
            student.setId(Integer.parseInt(stuId));
        }
        if(qName.equals("name")){
                       //这里就看出来Enum的重要性了。如果是我们上面设定的isgroupState的话就调用Enum类中的group相关字段。相反就调用Enum类中Student相关常量
            if(isgroupState)
                state = StudentEnum.groupName;
            else
                state = StudentEnum.stuName;

            return;
        }
        if(qName.equals("age")){
            state = StudentEnum.age;  //把状态标注为枚举中的age
            return;
        }
        if(qName.equals("sex")){
            state = StudentEnum.sex;  //同上
            return;
        }
        if(qName.equals("group")){
            group = new Group();  //如果为group那么先要初始化Group这个类,方便调用group类中的方法
            isgroupState = true; //因为默认isgroupState的状态为false。这里如果是group那么自然状态就变成了true
            return;
        }
                //group类中只有2个字段,而name在我们上述中已经有了判断。那么id跟Student一样先判断qName是否是id,再判断是否是groupState中的id,如果是就把state状态标注成Enum中的groupId.
        if(qName.equals("id")){
            if(isgroupState){
                state = StudentEnum.groupId;
                return;
            }
        }

    }
    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        if(state == StudentEnum.none){
            return;
        }
        //定义一个String类,存放characters方法中给出了三个参数.
        String str = new String(ch,start,length);
        //通过switch ,case分别把每个字段记录进去并通过student,group类中的set方法来进行设定。设定完毕后一定要把每个状态标注成none
        switch (state) {
        case stuName:
            student.setName(str);
            state = StudentEnum.none;
            break;
        case age:
            student.setAge(Integer.parseInt(str));
            state = StudentEnum.none;
            break;
        case sex:
            student.setSex(str);
            state = StudentEnum.none;
            break;
        case groupId:
            group.setId(Integer.parseInt(str));
            state = StudentEnum.none;
            break;
        case groupName:
            group.setName(str);
            state = StudentEnum.none;
            break;

        default:
            break;
        }
    }
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
               //这里是指在什么节点结束。xml内容我们是以</group></Student>为结束的因此这里还是根据qName来判断并标注状态。
        if(qName.equals("group")){
            isgroupState = false;
            student.setGroup(group); //通过student类中的.setGroup方法把group中的内容追加到Student类中
            return;
        }
        if(qName.equals("student")){
            students.add(student);  //最后把student类中的内容全部加载到students这个集合中
            return;
        }
    }
    @Override
    public void endDocument() throws SAXException {
        // TODO Auto-generated method stub
        super.endDocument();
    }

}
                        

StudentParser

StudentParser这个类中内容是我们SAX解析中的重点。同DOM一样也是一个解析器,通过逐步读取数据的方式进行解析不需要一下子把数据读取到内容中后再解析。

【Test测试】

package View;

import java.io.IOException;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.SAXException;

import Entity.Student;
import Tool.StudentParser;

public class Test {

	public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {                //调用SAXParserFactory以及SAXParer工厂类。
		SAXParserFactory factory = SAXParserFactory.newInstance();
		SAXParser parser = factory.newSAXParser();
		StudentParser handler = new StudentParser();  //初始化我们的解析器

		parser.parse("C:/Users/IBM_ADMIN/Desktop/xml/student.xml", handler);//通过parser.parse方法指定文件地址以及加载我们的解析器

		List<Student> students = handler.getResult();  //调用解析中的.getResult方法来调用students集合中的内容。
		//循环这个集合并打印
		for(Student stu:students){
			System.out.println(stu);
		}

	}

}

【结果】

下面结果可以看出我们成功的对XML文件中的内容进行了解析。日后比如说有个Group4,并有了新的成员的情况下,我们也不需要再重写我们的代码。只要xml结构不变,那么内容也会自动的被读取。

Student [age=19, group=Group [id=1, name=Group1], id=1, name=tonyliu, sex=男]
Student [age=18, group=Group [id=2, name=Group2], id=2, name=Susywang, sex=女]
Student [age=35, group=Group [id=3, name=Group3], id=3, name=JackZhang, sex=男]
时间: 2024-10-30 07:13:12

【文件处理】xml 文件 SAX解析的相关文章

Android中java文件与XML文件的协作过程

android是使用XML布局文件来定义界面,不是用Java代码来定义界面,所以说所有组件都提供了两种方式来控制组件的行为. 1. 在XML布局文件中通过XML属性进行时控制 2. 在Java程序代码中通过调用方法进行时控制. 实际上不管使用哪种方式,他们控制android用户界面行为的本质是完全一样的.大部分时候,控制UI组件的XML属性还有对应的方法. 对于View类而言,他是所有UI组件的基类,因此他包含的XML属性和方法时所有组件可以使用的.XML文件布局相对简单,常用的几种属性练熟就基

浅试txt文件与xml文件互相转换

最近遇到了txt文件和xml文件互相转换的问题,于是自己写了写,不算深,只是简单的互相转换,下面把代码共享一下,欢迎大家指点. 先看结果: 这是数据表里面查询出来的  select * from 表名 将数据表导出到txt文件中: 将上述的txt文件转换成xml文件: 由于屏幕截图问题,一个屏没截完整,最后没问题的. 又将xml文件转换成txt文件 : 第一步:获得txt文件数据源,首先找一个数据表把里面的数据导出到txt文件中,以逗号隔开.如下: 配置文件和读取数据类就不多说了,默认的 . 从

关于跨域策略文件crossdomain.xml文件

下载flexpaper源码修改后做成swf阅读器,要加入待阅读的swf文件,可以在flex里调用js的方法来获取swf文件的路径的方法,在js只专注获取路径就行,等着flex来调用:但这里会遇到一个问题那就是出现安全问题,如下的提示: Error #2044: 未处理的 onDocumentLoadedError:. text=Error #2048: 安全沙箱冲突:http://localhost:8080/UpLoadAndDownLoad/FlexPaper.swf 不能从 http://

解析xml文件并且输出(SAX解析器)

本文解析三个xml文件,难度依次增加 文件1:p1.xml <?xml version="1.0" encoding="UTF-8" ?> <persons> <person> <name>张三</name> <age>22</age> </person> </persons> 文件2:p2.xml <?xml version="1.0&quo

iOS中的数据解析(XML,JSON),SAX解析,DOM解析

第三方 SAT解析 #import "SAXTableViewController.h" #import "Student.h" @interface SAXTableViewController ()<NSXMLParserDelegate> @property (nonatomic, retain) NSMutableArray *dataSourse; // 存储学生对象 @property (nonatomic, retain) Student

Android解析XML之SAX解析器

SAX(Simple API for XML)解析器是一种基于事件的解析器,它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的.当事件源产生事件后,调用事件处理器相应的处理方法,一个事件就可以得到处理.在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事件处理器才能够根据提供的事件信息来决定自己的行为. SAX解析器的优点是解析速度快,占用内存少.非常适合在Android移动设备中使用. SAX相关类及API DefaultHandler:是一个事

XML之SAX解析模型

DOM解析会把整个XML文件全部映射成Document里的树形结构,当遇到比较大的文件时,它的内存占用很大,查找很慢 SAX就是针对这种情况出现的解决方案,SAX解析器会从XML文件的起始位置起进行解析,同时根据已经定义好的事件处理器,来决定当前所解析的部分是否有必要进行记录并存储 import java.io.File; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; public c

XML的sax解析

1)两种解析方式 dom解析:一次性把整个xml文件读入内容,构建document树. 问题:比较消耗内存     不适合读取大文件 sax解析: 为了解决读取大文件的问题,引入sax解析 原理:读取一点(xml的某个部分),解析一点 sax,simple api for xml 2) sax的api 官方jaxp的sax .  org.xm.sax.* 2.1 读取xml文件 a)创建SAXParserFactory对象 b)获取一个SAXParser对象 c)获取一个XMLReader对象

使用jaxp对比xml进行SAX解析

package cn.itcast.sax; import java.io.IOException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler;

XML(三)Sax解析XML

  两种解析方式: dom4j 和 sax 解析思想: book2.xml <?xml version="1.0" encoding="UTF-8"?> <书架> <书> <书名>JAVA</书名> <作者>XXXXXX</作者> <售价>23333</售价> </书> <书> <书名>ANDROID</书名>