一、sax简介

  SAX是事件驱动型的XML解析方式。顺序读取XML文件,生成事件,传播到用户定义的回调方法中来处理XML文件。

  优点:

    分段处理xml,而不是将整个xml一次加载进内存,内存占用少,速度快。

  缺点:

    顺序访问,不能回退。编码复杂,需要用户把控数据结构。

二、使用流程

  1.创建工厂

SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();

  2.设置工厂属性(可选)

saxParserFactory.setValidating(true); // 是否验证xml,默认false
saxParserFactory.setNamespaceAware(true); // 是否展示命名空间 默认false

  3.生成解析器

SAXParser parser = saxParserFactory.newSAXParser();

  4.设置解析器属性(可选)

parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema"); // 验证模式下必须

  5.获取XMLReader(可选)

XMLReader reader = parser.getXMLReader();

  6.设置XMLReader属性(可选)

reader.setContentHandler(new MyDefalutHandler()); // 内容处理器
reader.setEntityResolver(new MyEntityResolver()); // schama解析器
reader.setErrorHandler(new MyErrorHandler()); // 异常处理器

  7.解析xml文件

reader.parse(SaxDemo.class.getResource("/").getPath() + "/saxDemo.xml");
  或者
parser.parse(SaxDemo.class.getResource("/").getPath() + "/saxDemo.xml", new DefaultHandler());

  SAXParser和XMLReader都可以对xml进行解析,但是SAXParser将异常处理、内容处理和schema解析放到一个handler中进行重载,个人觉得职责划分不是很清晰,建议使用XMLReader。

三、常规使用代码示例

saxDemo.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:aop="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd" default-autowire="byName"> <aop:annotation-driven></aop:annotation-driven> <util:map key-type="java.lang.String" value-type="java.lang.String">
<entry key="key" value="value"></entry>
</util:map> <bean id="commonMap" class="java.util.HashMap">
<constructor-arg>
<map>
<entry key="key" value="value"></entry>
</map>
</constructor-arg>
</bean>
</beans>

MyDefalutHandler

public class MyDefalutHandler extends DefaultHandler{
@Override
public void startDocument() throws SAXException {
System.out.println("startDocument()");
} @Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
StringBuilder builder = new StringBuilder();
int length = attributes.getLength();
if (length > 0) {
for (int i = 0; i < length; i++) {
builder.append(attributes.getLocalName(i).trim())
.append(":")
.append(attributes.getValue(i).trim())
.append(" ");
}
} System.out.println(String.format("startElement uri=%s localName=%s qname=%s attributes=%s", uri, localName, qName, builder));
} @Override
public void characters(char[] ch, int start, int length) throws SAXException {
String content = new String(ch, start, length);
if (StringUtils.isNotBlank(content)) {
System.out.println("characters=" + content);
}
} @Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.println(String.format("startElement uri=%s localName=%s qname=%s", uri, localName, qName));
} @Override
public void endDocument() throws SAXException {
System.out.println("endDocument()");
}
}

测试类

 public class SaxDemo {
public static void main(String[] args) throws Exception {
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
// saxParserFactory.setValidating(true); // 是否验证xml,默认false
// saxParserFactory.setNamespaceAware(true); // 是否展示命名空间 默认false
SAXParser parser = saxParserFactory.newSAXParser();
// parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
XMLReader reader = parser.getXMLReader();
reader.setContentHandler(new MyDefalutHandler()); // 内容处理器
// reader.setEntityResolver(new MyEntityResolver()); // schama解析器
// reader.setErrorHandler(new MyErrorHandler()); // 异常处理器
reader.parse(SaxDemo.class.getResource("/").getPath() + "/saxDemo.xml");
}
}

测试结果

startDocument()
startElement uri= localName= qname=beans attributes=xmlns:http://www.springframework.org/schema/beans xmlns:xsi:http://www.w3.org/2001/XMLSchema-instance xmlns:util:http://www.springframework.org/schema/util xmlns:aop:http://www.springframework.org/schema/cache xsi:schemaLocation:http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd default-autowire:byName
startElement uri= localName= qname=aop:annotation-driven attributes=
startElement uri= localName= qname=aop:annotation-driven
startElement uri= localName= qname=util:map attributes=key-type:java.lang.String value-type:java.lang.String
startElement uri= localName= qname=entry attributes=key:key value:value
startElement uri= localName= qname=entry
startElement uri= localName= qname=util:map
startElement uri= localName= qname=bean attributes=id:commonMap class:java.util.HashMap
startElement uri= localName= qname=constructor-arg attributes=
startElement uri= localName= qname=map attributes=
startElement uri= localName= qname=entry attributes=key:key value:value
startElement uri= localName= qname=entry
startElement uri= localName= qname=map
startElement uri= localName= qname=constructor-arg
startElement uri= localName= qname=bean
startElement uri= localName= qname=beans
endDocument()

结果中可以看到uri和localName都是空,而且对aop:annotation-driven之类的解析不是很友好

打开测试类saxParserFactory.setNamespaceAware(true)的注释,执行结果如下

startDocument()
startElement uri=http://www.springframework.org/schema/beans localName=beans qname=beans attributes=schemaLocation:http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd default-autowire:byName
startElement uri=http://www.springframework.org/schema/cache localName=annotation-driven qname=aop:annotation-driven attributes=
startElement uri=http://www.springframework.org/schema/cache localName=annotation-driven qname=aop:annotation-driven
startElement uri=http://www.springframework.org/schema/util localName=map qname=util:map attributes=key-type:java.lang.String value-type:java.lang.String
startElement uri=http://www.springframework.org/schema/beans localName=entry qname=entry attributes=key:key value:value
startElement uri=http://www.springframework.org/schema/beans localName=entry qname=entry
startElement uri=http://www.springframework.org/schema/util localName=map qname=util:map
startElement uri=http://www.springframework.org/schema/beans localName=bean qname=bean attributes=id:commonMap class:java.util.HashMap
startElement uri=http://www.springframework.org/schema/beans localName=constructor-arg qname=constructor-arg attributes=
startElement uri=http://www.springframework.org/schema/beans localName=map qname=map attributes=
startElement uri=http://www.springframework.org/schema/beans localName=entry qname=entry attributes=key:key value:value
startElement uri=http://www.springframework.org/schema/beans localName=entry qname=entry
startElement uri=http://www.springframework.org/schema/beans localName=map qname=map
startElement uri=http://www.springframework.org/schema/beans localName=constructor-arg qname=constructor-arg
startElement uri=http://www.springframework.org/schema/beans localName=bean qname=bean
startElement uri=http://www.springframework.org/schema/beans localName=beans qname=beans
endDocument()

四、验证xml

如果我们使用ide,得益于ide的验证插件,编写xml的时候能规避掉一部分输入错误导致的格式异常。但是如果是通过xml进行rpc调用,我们可能需要悲观的设定得到的xml并不一定是正确的,验证xml是否满足既定格式就显得十分重要了。

取消测试类的saxParserFactory.setValidating(true),开启xml验证功能。

警告: 已启用验证, 但未设置 org.xml.sax.ErrorHandler, 这可能不是预期结果。解析器将使用默认 ErrorHandler 来输出前 0 个错误。请调用 'setErrorHandler' 方法以解决此问题。
Error: URI=file:///D:/idea/springboot2/target/classes//saxDemo.xml Line=2: 文档无效: 找不到语法。
Error: URI=file:///D:/idea/springboot2/target/classes//saxDemo.xml Line=2: 文档根元素 "beans" 必须匹配 DOCTYPE 根 "null"。

根据提示,创建一个异常处理器

public class MyErrorHandler implements ErrorHandler {

    @Override
public void warning(SAXParseException exception) throws SAXException {
System.out.println("------------warning------------");
throw exception;
} @Override
public void error(SAXParseException exception) throws SAXException {
System.out.println("------------error------------");
throw exception;
} @Override
public void fatalError(SAXParseException exception) throws SAXException {
System.out.println("------------fatalError------------");
throw exception;
}
}

取消测试类reader.setErrorHandler(new MyErrorHandler())的注释

Exception in thread "main" org.xml.sax.SAXParseException; systemId: file:///D:/idea/springboot2/target/classes//saxDemo.xml; lineNumber: 2; columnNumber: 7; 文档无效: 找不到语法。

还是异常!!!

出现这个问题的原因是sax不知道遵循哪个xml规范

取消测试类parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema")的注释,程序正常执行了。

五、自定义标签

maven工程下,resources目录创建META-INF文件夹,生成2个文件:saxDemo.schemas user.xsd

saxDemo.schemas内容:

http\://www.ym.com/schema/user.xsd=META-INF/user.xsd

user.xsd内容

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.ym.com/schema/user" targetNamespace="http://www.ym.com/schema/user"
elementFormDefault="qualified">
<xsd:element name="user">
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="userName" type="xsd:string" />
<xsd:attribute name="email" type="xsd:string" />
</xsd:complexType>
</xsd:element>
</xsd:schema>

修改samDemo.xml文件为:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:user="http://www.ym.com/schema/user"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.ym.com/schema/user http://www.ym.com/schema/user.xsd"
default-autowire="byName">
<user:user id="userTag" userName="userName" email="email"></user:user>
</beans>

执行测试代码

------------fatalError------------
Exception in thread "main" org.xml.sax.SAXParseException; systemId: http://www.ym.com/schema/user.xsd; lineNumber: 1; columnNumber: 50; 在 publicId 和 systemId 之间需要有空格。

抛出异常

为什么spring的标签没啥问题,而我们自定义的不行呢?这是因为spring的标签可以从网络上获取,但是我们自定义的基本上都在我们本地,而且很多时候我们也不希望从网络中获取这些资源,更希望使用本地jar包中的。

EntityResolver的作用就是从本地加载标签资源,验证xml的正确性。

创建MyEntityResolver从META-INF下读取资源

(代码来自spring源码org.springframework.beans.factory.xml.PluggableSchemaResolver,删除了所有日志的内容)

public class MyEntityResolver implements EntityResolver {

    private volatile Map<String, String> schemaMappings;
private final String schemaMappingsLocation = "META-INF/saxDemo.schemas";
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
if (systemId != null) {
String resourceLocation = getSchemaMappings().get(systemId);
if (resourceLocation != null) {
Resource resource = new ClassPathResource(resourceLocation, Thread.currentThread().getContextClassLoader());
try {
InputSource source = new InputSource(resource.getInputStream());
source.setPublicId(publicId);
source.setSystemId(systemId);return source;
}
catch (FileNotFoundException ex) {
}
}
}
return null;
} private Map<String, String> getSchemaMappings() {
Map<String, String> schemaMappings = this.schemaMappings;
if (schemaMappings == null) {
synchronized (this) {
schemaMappings = this.schemaMappings;
if (schemaMappings == null) {try {
Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.schemaMappingsLocation, Thread.currentThread().getContextClassLoader());
Map<String, String> mappingsToUse = new ConcurrentHashMap<>(mappings.size());
CollectionUtils.mergePropertiesIntoMap(mappings, mappingsToUse);
schemaMappings = mappingsToUse;
this.schemaMappings = schemaMappings;
}
catch (IOException ex) {
throw new IllegalStateException("Unable to load schema mappings from location [" + this.schemaMappingsLocation + "]", ex);
}
}
}
}
return schemaMappings;
}
}

现在打开测试代码reader.setEntityResolver(new MyEntityResolver())的注释

startDocument()
23:23:53.832 [main] DEBUG com.ym.xml.MyEntityResolver - Loading schema mappings from [META-INF/saxDemo.schemas]
23:23:53.839 [main] DEBUG com.ym.xml.MyEntityResolver - Loaded schema mappings: {http://www.ym.com/schema/user.xsd=META-INF/user.xsd}
startElement uri=http://www.springframework.org/schema/beans localName=beans qname=beans attributes=schemaLocation:http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.ym.com/schema/user http://www.ym.com/schema/user.xsd default-autowire:byName default-lazy-init:default default-merge:default
23:23:54.614 [main] DEBUG com.ym.xml.MyEntityResolver - Found XML schema [http://www.ym.com/schema/user.xsd] in classpath: META-INF/user.xsd
startElement uri=http://www.ym.com/schema/user localName=user qname=user:user attributes=id:userTag userName:userName email:email
startElement uri=http://www.ym.com/schema/user localName=user qname=user:user
startElement uri=http://www.springframework.org/schema/beans localName=beans qname=beans
endDocument()

七、总结

  本文介绍了sax的基本概念、调用流程、常用的使用方式。

  saxParserFactory.setValidating(true) 开启验证功能

  setNamespaceAware(true) 生成详细的事件记录

  setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema") 使用xsd验证规则

  setEntityResolver(new MyEntityResolver())  使用自定义标签

  setErrorHandler(new MyErrorHandler()) 自定义异常处理

  

  

  

  

sax解析xml,验证格式并支持自定义标签的更多相关文章

  1. 利用freemarker+SAX解析xml的方式对excel文件字段校验

    利用freemarker对参数进行校验这篇文章主要用到的技术点: 自定义注解的使用反射机制SAX解析xmlFreemarker的运用我们在工作中经常需要上传excel文件,然后在对文件中的字段进行校验 ...

  2. DOM&SAX解析XML

    在上一篇随笔中分析了xml以及它的两种验证方式.我们有了xml,但是里面的内容要怎么才能得到呢?如果得不到的话,那么还是没用的,解析xml的方式主要有DOM跟SAX,其中DOM是W3C官方的解析方式, ...

  3. cocos2d-x 3.0 使用Sax解析xml文件(中国显示器问题解决)

    今天是个好日子.我以为事情可以变得,明天是个好日子.打开门儿春风... 恩,听着歌写文档生活就是这么享受. 今天曾经的邻居大神突然在qq上赞了我一下,这让我异常激动啊.. 这还要从前前前几天说起,那会 ...

  4. JavaWeb学习日记----SAX解析XML

    1.SAX解析XML文档的方式: 与DOM方式解析不同,DOM方式解析是根据XML的层级结构在内存中分配一个树形结构,把xml的标签,属性和文本都封装成对象.优点是可以很方便实现增删改操作.缺点是,如 ...

  5. Python:使用基于事件驱动的SAX解析XML

    SAX的特点: 是基于事件的 API 在一个比 DOM 低的级别上操作 为您提供比 DOM 更多的控制 几乎总是比 DOM 更有效率 但不幸的是,需要比 DOM 更多的工作 基于对象和基于事件的接口 ...

  6. Dom,pull,Sax解析XML

    本篇随笔将详细讲解如何在Android当中解析服务器端传过来的XML数据,这里将会介绍解析xml数据格式的三种方式,分别是DOM.SAX以及PULL. 一.DOM解析XML 我们首先来看看DOM(Do ...

  7. Android之SAX解析XML

    一.SAX解析方法介绍 SAX(Simple API for XML)是一个解析速度快并且占用内存少的XML解析器,非常适合用于Android等移动设备. SAX解析器是一种基于事件的解析器,事件驱动 ...

  8. Android 使用pull,sax解析xml

    pull解析xml文件 1.获得XmlpullParser类的引用 这里有两种方法 //解析器工厂 XmlPullParserFactory factory=XmlPullParserFactory. ...

  9. JAVA使用SAX解析XML文件

    在我的另一篇文章(http://www.cnblogs.com/anivia/p/5849712.html)中,通过一个例子介绍了使用DOM来解析XML文件,那么本篇文章通过相同的XML文件介绍如何使 ...

随机推荐

  1. python学习 day5 (3月6日)

    字典映射,{}键值对,key 唯一的 ,可哈希,容器型数据类型 可变的(不可哈希): 字典 列表 集合 都不可做键 不可变的(可哈希): 数字 字符串 bool 元组 frozeset() 可以做键 ...

  2. delphi 中的win32 以外到平台的字符串处理一定慢吗?(转载)

    原始连接:http://rvelthuis.blogspot.tw/2018/01/strings-on-other-platforms-than-32-bit.html Strings too sl ...

  3. Ubuntu显示实时网速CPU内存等参数

    添加库 sudo add-apt-repository ppa:fossfreedom/indicator-sysmonitor 更新软件列表 sudo apt-get update 安装indica ...

  4. 2018.11.01 NOIP训练 图论(线段树+倍增+dfs序)

    传送门 一道挺妙的题. 对于询问点(u,v),如右图所示,我们可以发现存在一个点m在u->v的路径中,m子树的点到u是最近的,m子树外到v是最近的.其中dis(u,m)=(dis(u,v)-1) ...

  5. w7 目录

    第17章 期中架构体系介绍 期中架构环境准备 01-期中架构内容简介 02-期中架构大酒楼详解 03-期中架构使用到的软件简介 04-期中架构运维角度观察与使用的软件 05-重头开始创建一台新的虚拟机 ...

  6. 学习fortran77基础语法

    Program ParamaterDefine Implicit None C FORTRAN变量名和关键字不区分大小写.但调用外部函数的话,需要在编译选项里指定 c 大小写等选项 因为链接器是区分大 ...

  7. 屏幕抓取程序 (位图DDB的例子)

    屏幕抓取程序的意思是将整个屏幕图显示在应用程序的用户区中,等价于截图.对桌面窗口的操作:首先得知道桌面窗口的宽和高,获取宽和高需要利用窗口的设备句柄,而获取设备句柄需要知道窗口句柄,这一系列的连串关系 ...

  8. 手把手教Electron+vue的使用

    .现如今前端框架数不胜数,尤其是angular.vue吸引一大批前端开发者,在这个高新技术快速崛起的时代,自然少不了各种框架的结合使用.接下来是介绍electron+vue的结合使用. 2.Elect ...

  9. (转)ASP.NET MVC 3和Razor中的@helper 语法

    转自:http://kb.cnblogs.com/page/102191/ ASP.NET MVC 3支持一项名为“Razor”的新视图引擎选项(除了继续支持/加强现有的.aspx视图引擎外).当编写 ...

  10. (转)mysql command line client打不开(闪一下消失)的解决办法

    转自:http://www.2cto.com/database/201209/153858.html 网上搜索到的解决办法: 1.找到mysql安装目录下的bin目录路径. 2.打开cmd,进入到bi ...