原文链接https://zhhll.icu/2020/xml/SAX/SAX解析/
由于DOM解析XML的弊端,一种替代的技术就是使用SAX解析。
SAX是基于事件模型的XML解析方式,不需要将整个XML文档加载到内存中,只需加载一部分即可开始解析,在处理过程中不会在内存中记录XML中的数据,占用的资源比较少,当程序处理满足一定条件时,可以立即停止解析,这样不必解析剩余的XML内容。
SAX解析主要涉及两个部分:解析器和事件处理器。解析器负责读取XML文档,并向事件处理器发送事件,如元素开始和结束事件;事件处理器则负责对事件做出响应,对传递的XML数据进行处理。
当SAX解析器解析到某类型节点时,会触发注册在该类型节点上的回调函数,继承SAX提供的DefaultHandler来重写相应事件的处理方法并进行注册即可。(事件是由解析器产生并通过回调函数发送给应用程序的,这种模式称为推模式)。
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;@Overridepublic 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;iSystem.out.println(attributes.getQName(i)+"--->"+attributes.getValue(i));}}}@Overridepublic 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);}}@Overridepublic void endDocument() throws SAXException {System.out.println("xml解析完毕");}@Overridepublic void startDocument() throws SAXException {System.out.println("开始读取xml文档");}});} catch (ParserConfigurationException | SAXException | IOException e) {throw new RuntimeException("SAX解析器构建失败",e);}}