SAX解析

SAX解析

原文链接https://zhhll.icu/2020/xml/SAX/SAX解析/

SAX解析介绍

由于DOM解析XML的弊端,一种替代的技术就是使用SAX解析。

SAX是基于事件模型的XML解析方式,不需要将整个XML文档加载到内存中,只需加载一部分即可开始解析,在处理过程中不会在内存中记录XML中的数据,占用的资源比较少,当程序处理满足一定条件时,可以立即停止解析,这样不必解析剩余的XML内容。

SAX处理机制

SAX解析主要涉及两个部分:解析器和事件处理器。解析器负责读取XML文档,并向事件处理器发送事件,如元素开始和结束事件;事件处理器则负责对事件做出响应,对传递的XML数据进行处理。

当SAX解析器解析到某类型节点时,会触发注册在该类型节点上的回调函数,继承SAX提供的DefaultHandler来重写相应事件的处理方法并进行注册即可。(事件是由解析器产生并通过回调函数发送给应用程序的,这种模式称为推模式)。

SAX接口介绍

  • SAXParserFactory 获取SAX解析器的工厂类
  • SAXParser SAX解析器的标准接口
监听器

SAX解析事件一共有四种监听器

  • EntityResolver 监听实体处理时间的监听器

    public interface EntityResolver {
    
        public abstract InputSource resolveEntity (String publicId,
                                                   String systemId)
            throws SAXException, IOException;
    
    }
    
  • DTDHandler 监听DTD处理事件的监听器

    public interface DTDHandler {
    
    
        // 解析DTD符号时触发
        public abstract void notationDecl (String name,
                                           String publicId,
                                           String systemId)
            throws SAXException;
    
    
        // 解析DTD中的未解析实体时触发
        public abstract void unparsedEntityDecl (String name,
                                                 String publicId,
                                                 String systemId,
                                                 String notationName)
            throws SAXException;
    
    }
    
  • ContentHandler 监听XML文档内容处理事件的监听器

    public interface ContentHandler
    {
    
        
        public void setDocumentLocator (Locator locator);
    
    
        // 开始处理文档时触发
        public void startDocument ()
            throws SAXException;
    
    
        // 处理文档结束时触发
        public void endDocument()
            throws SAXException;
    
    
        // 开始处理元素中的命名空间属性时触发(xmlns:prefix属性)
        public void startPrefixMapping (String prefix, String uri)
            throws SAXException;
    
    
        // 处理元素中的命名空间属性结束时触发(xmlns:prefix属性)
        public void endPrefixMapping (String prefix)
            throws SAXException;
    
    
        // 开始处理元素时触发
        public void startElement (String uri, String localName,
                                  String qName, Attributes atts)
            throws SAXException;
    
    
        // 处理元素结束时触发
        public void endElement (String uri, String localName,
                                String qName)
            throws SAXException;
    
    
        // 处理字符数据时触发
        public void characters (char ch[], int start, int length)
            throws SAXException;
    
    
        // 处理元素内容中可忽略的空白时触发
        public void ignorableWhitespace (char ch[], int start, int length)
            throws SAXException;
    
    
        // 处理指令时触发
        public void processingInstruction (String target, String data)
            throws SAXException;
    
    
        // 跳过实体时触发
        public void skippedEntity (String name)
            throws SAXException;
    }
    
  • ErrorHandler 监听解析错误的监听器

    public interface ErrorHandler {
    
    
       
        public abstract void warning (SAXParseException exception)
            throws SAXException;
    
    
        
        public abstract void error (SAXParseException exception)
            throws SAXException;
    
    
        
        public abstract void fatalError (SAXParseException exception)
            throws SAXException;
    
    }
    

这么多接口都进行实现那是不是太麻烦了呢,瞬间就不想用SAX来进行解析了,不过JAXP提供了一个类来很好的解决这个问题DefaultHandler,该类实现了这四个接口

public class DefaultHandler implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler

并对这些方法提供了空实现,通常只需要继承该类来重写我们需要关心的监听方法即可

public static SAXParser createDefaultParser(InputStream stream,DefaultHandler handler) throws ParserConfigurationException, SAXException, IOException {
    SAXParserFactory factory = SAXParserFactory.newInstance();
    SAXParser parser =  factory.newSAXParser();
    parser.parse(stream,handler);
    return parser;

}

public static void readMapper(String fileName){
        InputStream stream = ClassLoader.getSystemResourceAsStream("test.xml");
        SAXParser parser = null;


        try {
            parser = createDefaultParser(stream,new DefaultHandler(){
                // 当前元素
                private String currentTag;
                @Override
                public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {

                    System.out.println("开始处理元素"+qName);
                    currentTag = qName;

                    int length = attributes.getLength();
                    if(length > 0){
                        System.out.println(currentTag+"元素中包含属性");
                        for(int i = 0;i<length;i++){
                            System.out.println(attributes.getQName(i)+"--->"+attributes.getValue(i));
                        }
                    }
                    
                }

                @Override
                public void characters(char[] ch, int start, int length) throws SAXException {
                    String content = new String(ch,start,length);

                    if(content.trim().length() > 0){
                        System.out.println(currentTag+"元素中的值是"+content);
                    }
                }

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

                @Override
                public void startDocument() throws SAXException {
                    System.out.println("开始读取xml文档");
                }


            });
        } catch (ParserConfigurationException | SAXException | IOException e) {
            throw new RuntimeException("SAX解析器构建失败",e);
        }
    }

SAX的缺点

  • 由于不存储XML文档结构,需要开发人员自己负责维护多层节点之间的关系
  • 由于是流式处理,只能单向处理,无法回到之前处理过的节点
  • 不提供写文档的功能

DOM和SAX比较

  • 速度 DOM需要一次性装载整份文档,并将xml文档转为DOM数,速度较慢;SAX顺序解析XML文档,无需一次装载整份文档,速度较快
  • 重复访问 DOM转换为DOM树后,整个解析阶段DOM树常驻内存,非常适合重复访问,效率较高;SAX顺序解析XML文档,不会保存已访问的数据,不适合重复访问,如果需要重复访问需要再次开始解析
  • 内存要求 DOM整个解析阶段DOM树常驻内存,内存占用较多;SAX不保存已访问数据,内存占用低
  • 修改 DOM既可以读取节点内容,也可以修改节点内容;SAX只能用来读取,不可修改
  • 复杂度 DOM完全采用面向对象的思想,整份XML转为DOM树后,以面向对象的方式来操作各个Node对象即可;SAX采用事件驱动的方式,SAX解析器只负责触发事件,程序负责监听事件,并通过事件获取XML中的内容,比较麻烦
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拾光师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值