XML--02--解析-SAX方式

java操作xml简介

  • java里面操作xml的方法无非就是读与写,读出来才能谈后续的替换、查找等操作,java里面操作xml的方法也是五花八门的,我这里总结几种常用的方法,见下图:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

xml读:

sax,dom,jdom,dom4j

xml写:

dom,jdom,dom4j,xstream

sax:

  • 即Simple API for XML,它是java本身自带的类库,使用它不需要你引入任何其他的jar包,在xml的解析方面性能特别快,特别针对比较大的xml文档,处理起来很有优势。

dom:

  • 即jdk针对w3c dom结构标准的实现,虽然可以用来xml的解析与写入,不过在实际使用的状况来看,还是在写入方面使用的比较多,解析建议使用sax。

jdom:

  • 是一个第三方类库,我们使用的使用引入jdom.jar就可以使用了

dom4j:

  • "4j"这个词不读做“四j”,而是读作“for j”,意思是dom for java,也是一个第三方类库,我们使用时也需要引入它的jar包。

SAX方式

  • Java JDK自带的解析(SAXParserFactory SAXPaeser DefaultHandler)
  • 特点:基于事件模型的,一行一行的往下面执行解析的
  • startDocment startelement characters endElement endDocment

SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,

涉及两个部分:解析器事件处理器

  • 解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。
  • 解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
  • 事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。

在这里插入图片描述

备注说明:SAX API中主要有四种处理事件的接口,它们分别是ContentHandler,DTDHandler, EntityResolver 和 ErrorHandler

解析步骤:

  1. 创建一个SAXParserFactory对象

    SAXParserFactory factory=SAXParserFactory.newInstance();

  2. 获得解析器

    SAXParser parser=factory.newSAXParser();

  3. 调用解析方法解析xml
    这里的第一个参数可以传递文件、流、字符串、需要注意第二个参数
    (new DefaultHander) File file=new File(“girls.xml”);
    parser.parse(file,new DefaultHandler());

/**注解:—>这里的DefaultHandler表示
DefaultHandler类是SAX2事件处理程序的默认基类。它继承了EntityResolver、DTDHandler、
ContentHandler和ErrorHandler这四个接口。包含这四个接口的所有方法,所以我们在编写事件处理程序时,
可以不用直接实现这四个接口,而继承该类,然后重写我们需要的方法,所以在这之前我们先定义一个用于实现解析
方法如下:*/

  1. 创建一个MyHandler类来继承DefaultHandler并重写方法

    1. MyHandler extends DefaultHander

    2. 重写方法,快速记住方法(2个开始,2个结束,1一个文字(charactor–里面的内容))

    3. 2个开始:StartDocment(文档的开始)StartElement(元素的开始) 2个结束:endElement(元素的结束) endDocment(文档的结束,标志着xml文件的结束) 1个文字内容:charactor(文字内容)

  2. 创建一个集合把所解析的内容添加到集合
    分析:目的我们只是需要把xml里面的文字内容添加到我们的集合而不需要其他元素,所以我们需要进行判断得到

  3. 接步骤三 输出集合System.out.pritnln(list); 解析完成!

DefaultHandler重写的几个方法:

  • startDocument():文档解析开始时调用,该方法只会调用一次
  • startElement(String uri, String localName, String qName, Attributes attributes):标签(节点)解析开始时调用
  1. uri:xml文档的命名空间
  2. localName:标签的名字
  3. qName:带命名空间的标签的名字
  4. attributes:标签的属性集
  • characters(char[] ch, int start, int length):解析标签的内容的时候调用
  1. ch:当前读取到的TextNode(文本节点)的字节数组
  2. start:字节开始的位置,为0则读取全部
  3. ength:当前TextNode的长度
  • endElement(String uri, String localName, String qName):标签(节点)解析结束后调用
  • endDocument():文档解析结束后调用,该方法只会调用一次

记住这张图:

在这里插入图片描述
在这里插入图片描述

案例 1:

  • 我们将对这个xml文件进行SAX解析
    在这里插入图片描述

第一步 :初始化一个Girl类:


public class Girl {
    private String id;
    private String name;
    private String age;
    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 getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Girl [name=" + name + ", age=" + age + "]";
    }



}

第二步:编辑执行器Handler

继承DefaultHandler

import com.cy.pojo.Girl;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

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

public class MyHandler  extends DefaultHandler {
    private List<Girl> girls;
    private Girl girl;
    private String tag;

    public List<Girl> getGirls() {
        return girls;
    }

    public void setGirls(List<Girl> girls) {
        this.girls = girls;
    }

    public Girl getGirl() {
        return girl;
    }

    public void setGirl(Girl girl) {
        this.girl = girl;
    }

    public String getTag() {
        return tag;
    }

    public void setTag(String tag) {
        this.tag = tag;
    }



    @Override
    public void startDocument() throws SAXException {
        //  因为这个方法只调用一次,所以在开始的时候就可以实例化集合
        System.out.println("sax解析开始");
        girls=new ArrayList<>();
    }

    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
        System.out.println("sax解析结束");
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        //  这个方法,只有当开始一个元素的时候才会调用,
// 通过分析,当外部开始元素为girl的时候,需要将girl实例化

//      将tag赋值
        tag=qName;
        if ("girl".equals(qName)) {
            girl=new Girl();
        }

    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
//        这句话,必须写,因为,当sax解析完一个元素的时候,会自动认为换行符是一个字符,会继续执行 character 方法 。如果不写,就会造成没有数据的现象。
        tag="";

//      这个方法,当到了元素结尾的时候,会调用,应该在这里,将对象添加到集合里面去。
        if ("girl".equals(qName)) {
            girls.add(girl);
        }

    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        //      这里是内容,但是,无法直接判断属于哪一个元素。
        String string = new String(ch, start, length);
        if ("name".equals(tag)) {//判断当前内容,属于哪一个元素。
            girl.setName(string);
        }else if ("age".equals(tag)) {
            girl.setAge(string);
        }//这两种情况,表示 当前语句执行在 girls 标签内。

    }
}

第三步: 解析


public class Sax03 {
    public static void main(String[] args) {
//      1.创建对象
        SAXParserFactory newInstance = SAXParserFactory.newInstance();
        try {
//      2.获取解析器 
            SAXParser saxParser = newInstance.newSAXParser();
//      3.调用方法开始解析xml   
            File file = new File("girls.xml");
            MyHandler dh = new MyHandler();
            saxParser.parse(file, dh);
            List<Girl> girls=dh.getGirls();
//      4.输出集合
            System.out.println(girls);
        } catch (ParserConfigurationException | SAXException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

加粗样式

案例 2:

要解析的msg.xml:
在这里插入图片描述

需求:

不让你找到optionName标签内的文本内容了,直接让你读出来整个文档

编辑执行器Handler

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

public class XmlHandler extends DefaultHandler {
    @Override
    public void startDocument() throws SAXException {
        System.out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
    }

    @Override
    public void endDocument() throws SAXException {
        System.out.print("解析完毕");
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        System.out.print("<");
        System.out.print(qName);
        if(attributes!=null){
           for (int i = 0;i<attributes.getLength(); i++){
               System.out.print(" "+attributes.getQName(i)+"=\""+attributes.getValue(i)+"\"");
           }
		 }
           System.out.print(">");
    }


    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        System.out.print("</");
	    System.out.print(qName);
	    if (qName.equals("message")){
            System.out.println(">");
        }else {
            System.out.print(">");
        }

    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        System.out.print(new String(ch,start,length));
    }
}

解析:

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;

public class XmlReader2 {

    public static void main(String[] args) throws Exception {
        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
        
        SAXParser saxParser = saxParserFactory.newSAXParser();
        
        File file = new File("src\\main\\resources\\mapper\\msg.xml");
        
        saxParser.parse(file,new XmlHandler());
        
    }
}

在这里插入图片描述

封装逻辑:

在这里插入图片描述

总结:

  • 可以看到,sax定义了startDocument,endDocument,startElement,endElement,characters这些事件,
  • 针对上面的例子来说,startDocument,endDocument只会调用一次,因为只有一个文档嘛,自然就只有一次文档的开始与文档的结束。
  • startElement,endElement,characters事件都会调用多次,其中characters用于获取元素内的文本内容。

SAX的优点:

  • 解析速度快
  • 占用内存少

SAX的缺点:

  • 无法知道当前解析标签(节点)的上层标签,及其嵌套结构,仅仅知道当前解析的标签的名字和属性,要知道其他信息需要程序猿自己编码
  • 只能读取XML,无法修改XML
  • 无法随机访问某个标签(节点)

SAX解析适用场合

  • 对于CPU资源宝贵的设备,如Android等移动设备
  • 对于只需从xml读取信息而无需修改xml

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值