SAX 是什么?
用于读取和操作 XML 文件的标准是文档对象模型(Document Object Model,DOM)。遗憾的是,DOM 方法涉及读取整个文件并将该文件存储在一个树结构中,而这样可能是低效的、缓慢的,并且很消耗资源。
一种替代技术就是 Simple API for XML,或称为 SAX。SAX 允许您在读取文档时处理它,从而不必等待整个文档被存储之后才采取操作。
SAX 是由 XML-DEV 邮件列表的成员开发的,现在对应的 Java 版本是 SourceForge 项目(请参阅 参考资料)。该项目的目的是为 XML 的使用提供一种更自然的手段 —— 换句话说,也就是不涉及 DOM 所必需的开销和概念跳跃。
项目的成果是一个基于事件 的 API。解析器向一个事件处理程序发送事件,比如元素的开始和结束,而事件处理程序则处理该信息。然后应用程序才能够处理该数据。原始的文档仍然保持原样,但是 SAX 提供了操作数据的手段,因此数据可以用于另一个进程或文档。
SAX 没有官方的标准机构,由万维网联盟(Wide Web Consortium,W3C)或其他官方机构维护,但它是 XML 社区事实上的标准。
- SAX 处理涉及以下步骤:
1. 创建一个事件处理程序。
2. 创建 SAX 解析器。
3. 向解析器分配事件处理程序。
4. 解析文档,并将每个事件发送到事件处理程序。
基于事件的处理的优点和缺点
这种处理的优点非常类似于流媒体的优点。不需要等待所有数据都处理完成,就可以立即开始分析。而且,由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优点。事实上,应用程序甚至不必解析整个文档;它可以在某个条件得到满足时停止解析。一般来说,SAX 比 DOM 快许多。
另一方面,由于应用程序没有以任何方式存储数据,使用 SAX 来更改数据或在数据流中往后移是不可能的。
- DOM 和基于树的处理
DOM 是处理 XML 数据的传统方法。使用 DOM 时,数据以树状结构的形式被加载到内存中
基于树的处理的优点和缺点
DOM 以及广义的基于树的处理具有几个优点。首先,由于树在内存中是持久的,因此修改它可以使应用程序对数据和结构作出更改。它还可以随时在树中上下导航,而 SAX 是一次性的处理。此外,DOM 使用起来也简单很多。
另一方面,在内存中构造这样的树涉及大量的开销。大型文件完全占用系统内存容量的情况并不少见。此外,创建 DOM 树非常耗时
- 如何在 SAX 和 DOM 之间选择
选择 DOM 还是选择 SAX 取决于下面几个因素:
* 应用程序的用途:如果打算对数据作出更改并将它输出为 XML,DOM 通常是适当的选择。并不是说 SAX 不能更改数据,而是操作起来复杂得多,因为您必须更改数据的拷贝而不是数据本身。
* 数据量:对于大型文件,SAX 是更好的选择。
* 数据使用的方式:如果只使用数据的少量部分,那么使用 SAX 来将该部分数据提取到应用程序中可能更好。另一方面,如果您需要回头引用已处理过的大量信息,那么应该选择 DOM。
* 速度要求:SAX 实现通常要比 DOM 实现更快。
重要的是,SAX 和 DOM 并不相互排斥。您可以使用 DOM 来创建 SAX 事件流,也可以使用 SAX 来创建 DOM 树。事实上,用于创建 DOM 树的大多数解析器实际上都使用 SAX 来完成这个任务!
使用样例
public class XmlDocumentUtil {
public static void main(String[] str) throws Exception {
XmlDocumentUtil xmlUtil=new XmlDocumentUtil();
//xmlUtil.XmlFilterReader();
//xmlUtil.serializerXml();
xmlUtil.readXml();
}
public void readXml() {
DocumentBuilderFactory xmlBuild=DocumentBuilderFactoryImpl.newInstance();
//DocumentBuilderFactory.newInstance();
xmlBuild.setValidating(false);
xmlBuild.setIgnoringComments(true);
xmlBuild.setIgnoringElementContentWhitespace(true);
try {
File xml=new File("atta.xml");
DocumentBuilder build=xmlBuild.newDocumentBuilder();
build.setEntityResolver(new DefaultEntityResolver());
Document doc= build.parse(xml);
//ErrorHandlerWrapper
Element root=doc.getDocumentElement();
NodeList nodeList=root.getChildNodes();
/*for(int i=0;i<nodeList.getLength();i++){
Node node=(Node)nodeList.item(i);
System.out.println(node.getNodeName()+":"+node.getNodeValue());
}*/
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* <p>功能:创建xml解析器<p>
* <p>
* <p>
*/
public void CreaterXmlreader() {
try {
/*方法1、获取xmlReader*/
XMLReader xmlReader= XMLReaderFactory.createXMLReader();
/*方法2、获取xmlReader*/
SAXParserFactory saxParserF=SAXParserFactory.newInstance();
saxParserF.setValidating(false);
SAXParser saxParser=saxParserF.newSAXParser();
xmlReader=saxParser.getXMLReader();
/*解析文档*/
xmlReader.setContentHandler(new XmlReaderHandler());
xmlReader.parse("");
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void serializerXml() throws ParserConfigurationException, SAXException, IOException{
SAXParserFactory spfFactory=SAXParserFactory.newInstance();
spfFactory.setValidating(false);
SAXParser saxParser=spfFactory.newSAXParser();
XMLReader xmlReader= saxParser.getXMLReader();
/*可接受xml,txt,html*/
Serializer serializer=SerializerFactory.getSerializer(OutputProperties.getDefaultMethodProperties("xml"));
serializer.setOutputStream(new FileOutputStream("output.xml"));
InputSource inSource=new InputSource("atta.xml");
xmlReader.parse(inSource);
}
public void XmlFilterReader() throws SAXException, ParserConfigurationException, IOException{
SAXParserFactory spfFactory=SAXParserFactory.newInstance();
spfFactory.setValidating(false);
SAXParser saxParser=spfFactory.newSAXParser();
XMLReader xmlReader= saxParser.getXMLReader();
XmlFilter xmlFilter=new XmlFilter(xmlReader);
//xmlFilter.setParent(xmlReader);
xmlFilter.setContentHandler(new XmlFilter());
xmlFilter.setErrorHandler(new XmlFilter());
InputSource inSource=new InputSource("atta.xml");
xmlFilter.parse(inSource);
}
/*转换xml*/
public void sampleTransFormXml() throws ParserConfigurationException, SAXException, TransformerConfigurationException, IOException{
SAXParserFactory saxPF=SAXParserFactory.newInstance();
saxPF.setValidating(false);
SAXParser saxParser=saxPF.newSAXParser();
XMLReader xmlReader=saxParser.getXMLReader();
TransformerFactory tfF=TransformerFactory.newInstance();
//Transformer tf=tfF.newTransformer();
SAXTransformerFactory saTF=(SAXTransformerFactory)tfF;
XMLFilter filter=saTF.newXMLFilter(new StreamSource("atta.xsl"));
filter.setParent(xmlReader);
Serializer serializer=SerializerFactory.getSerializer(OutputProperties.getDefaultMethodProperties("xml"));
serializer.setOutputStream(System.out);
filter.setContentHandler(serializer.asContentHandler());
InputSource inputSource=new InputSource("atta.xml");
filter.parse(inputSource);
}
}
class XmlFilter extends XMLFilterImpl{
@Override
public void startElement(String arg0, String arg1, String arg2, Attributes arg3) throws SAXException {
super.startElement(arg0, arg1, arg2, arg3);
}
public XmlFilter(XMLReader xmlReader){
super(xmlReader);
}
public XmlFilter(){
super();
}
@Override
public void startDocument() throws SAXException {
super.startDocument();
System.out.println("[xml filter] startDocument");
}
}
class XmlReaderHandler extends DefaultHandler{
@Override
public void startDocument() throws SAXException {
super.startDocument();
System.out.println("start parser document");
}
@Override
public void error(SAXParseException arg0) throws SAXException {
super.error(arg0);
}
}
名称空间
SAX 20 版的一个主要增强是添加了对名称空间的支持,从而允许开发人员无冲突地使用来源不同或用途不同的信息。这通常出现在生产环境中,因为生产环境中的 SAX 数据流中的数据来源非常广泛。
名称空间是一个概念范围,其中的所有名称都必须是唯一的。
例如,我过去常在这样一间办公室工作,我的名字和那里的一位客户相同。如果我在办公室,而接待员宣布 “Nick,请接 1 号电话”,那么每个人都知道她指的是我,因为我在 “办公室名称空间中”。类似地,如果她宣布 “Nick 在一号线上”,每个人都知道她指的是那位客户,因为呼叫者在办公室名称空间之外。
另一方面,如果我出了办公室,而她做出相同的宣布,混淆就可能产生,因为两种可能性都存在。
当 XML 数据库由多种来源组合而成时,同样的问题也会产生,比如本教程稍后将会详细描述的示例文件中修订过的调查信息。
由于名称空间的标识符必须是唯一的,因而使用统一资源定位符(或 URI)来指定它们。例如,本教程的示例数据的默认名称空间将使用 xmlns 属性来指定:
<?xml version="1.0"?>
<surveys xmlns="http://www.nicholaschase.com/surveys/" >
<response username="bob">
<question subject="appearance">A</question>
...
没有指定名称空间的任何节点都在默认名称空间 http://www.nicholaschase.com/surveys/ 中。实际的 URI 本身并没有表示任何意义。信息可能在也可能不在该地址,重要的是它必须是唯一的。
默认名称空间和没有名称空间之间的巨大区别是很重要的。在本例中,没有名称空间前缀的元素都在默认名称空间中。以前,当不存在默认名称空间时,那些元素就不在任何名称空间中。当您处理 关于属性的名称空间 时,这个区别就变得重要了。
您还可以创建次级名称空间,并向它们添加元素或属性。
指定名称空间
也可以为数据指定其他名称空间。例如,通过创建一个 revised 名称空间,您可以添加第二组数据,比如后期催眠,而不干扰原先的数据。
通常在文档的根元素上(但不是必须的)创建名称空间及其别名。当正在使用多个名称空间时,这个别名根据需要用作元素或属性的前缀,以指定正确的名称空间。请考虑下面代码:
<?xml version="1.0"?>
<surveys xmlns="http://www.nicholaschase.com/surveys/"
xmlns:revised="http://www.nicholaschase.com/surveys/revised/">
<response username="bob">
<question subject="appearance">A</question>
<question subject="communication">B</question>
<question subject="ship">A</question>
<question subject="inside">D</question>
<question subject="implant">B</question>
<revised:question subject="appearance">D</revised:question>
<revised:question subject="communication">A</revised:question>
<revised:question subject="ship">A</revised:question>
<revised:question subject="inside">D</revised:question>
<revised:question subject="implant">A</revised:question>
</response>
<response username="sue">
...
它使用了名称空间和别名 revised 来创建额外的 question 元素。
记住 revised: 不是名称空间,而是别名!实际的名称空间是 http://www.nicholaschase.com/surveys/revised/。
属性也可能属于某个特定的名称空间
即使声明了一个默认名称空间,没有前缀的属性也被认为是没有名称空间。这只是在 XML 推荐标准中定义的一个例外
名称空间的奇怪之处
SAX 解析器处理本地名称和 QName 的方式可能有点奇怪。例如,除非专门打开名称空间处理,否则默认的 Java 解析器就不会报告本地名称的值:
try {
SAXParserFactory spfactory = SAXParserFactory.newInstance();
spfactory.setValidating(false);
spfactory.setFeature("http://xml.org/sax/features/namespace-prefixes",
true);
spfactory.setFeature("http://xml.org/sax/features/namespaces",
true);
SAXParser saxParser = spfactory.newSAXParser();
如果不能获取信息,可尝试设置解析器的这些特性。
分享到:
相关推荐
本篇Java学习笔记旨在为读者提供一个深入理解Java的基础与进阶知识的框架,帮助初学者及有一定经验的开发者提升Java编程技能。 ### 一、Java入门与基本语法 #### 课程概述 Java课程旨在介绍面向对象编程的基本原则...
4. **学习笔记**: 学习笔记通常包含个人理解、实例代码和问题解决方案,对于初学者来说是很好的参考资料,可以了解他人在学习过程中遇到的问题和解决办法。 5. **API(应用程序接口)**: Dom4j的API文档是开发者的...
**DOM4J学习笔记** DOM4J是一个强大的Java XML API,它提供了丰富的XML处理功能,包括文档构建、解析、修改和查询。作为一个开源项目,DOM4J在XML处理领域具有广泛的用户基础,因其简单易用和高效性能而备受青睐。...
### 北京圣思园XML学习笔记核心知识点详解 #### XML概述 - **XML全称**:eXtensible Markup Language(可扩展标记语言) - **学习XML的原因**: - 数据交换的需求日益增长,XML成为了电子商务的重要基础之一。 - ...
【XML 高级学习笔记】 XML(Extensible Markup Language)是一种可扩展标记语言,与HTML类似,但其设计目标是存储和传输数据,而非呈现数据。XML允许用户自定义标签,使得它成为一种自描述的语言,并且是W3C的标准...
这份学习笔记涵盖了从操作系统基础到数据库应用的广泛主题,是Java初学者或希望巩固基础的开发者的重要资源。 1. **Unix学习基础**:Unix是许多服务器和开发环境常用的操作系统。了解Unix的基础知识,包括文件系统...
XML,全称Extensible Markup Language,可扩展标记语言,是一种用于标记数据的结构化语言,...通过这些学习资料,你将能够深入理解XML的各个方面,从基础语法到高级用法,从而在实际工作中更有效地处理和利用XML数据。
【CSS】 ...CSS描述了如何在媒体(如屏幕、打印机)上展示元素。通过CSS,你可以控制网页的...这些笔记涵盖了Web开发的基础知识,适合初学者入门,通过学习和实践,可以逐步掌握创建动态、响应式和数据驱动的网页应用。
**标题解析:** "Dom4j学习笔记" 这个标题明确指出了我们要探讨的主题——Dom4j。Dom4j是一个流行的Java库,用于处理XML文档。它提供了丰富的API,使得XML的读取、写入、操作变得简单易行。在学习笔记中,通常会涵盖...
这份"Java JDK 6学习笔记——ppt简体版"提供了关于这个关键版本的详细教程,适合初学者和有一定经验的开发者来深入理解Java编程。 首先,我们要了解Java JDK是什么。Java Development Kit,简称JDK,是Oracle公司...
在本资源包中,你将找到《轻松搞定XML》这本书的学习笔记和配套源代码,这些都是作者在深入研读过程中积累的宝贵资料。 XML的核心特性包括自描述性、结构化和平台及语言无关性。自描述性意味着每个元素都有自己的...
Java JDK 6学习笔记是针对Java开发环境的重要参考资料,它涵盖了Java Development Kit(JDK)6版本的关键特性和...这份学习笔记将指导读者逐步探索和理解Java编程世界的深度和广度,为日后的开发工作打下坚实的基础。
这个"java学习笔记JDK6课件和课本代码"资源很可能是包含了一系列的教程、PPT课件、示例代码和练习题,帮助初学者或者需要回顾JDK 6特性的开发者深入理解和实践。通过这些资料,你可以学习如何使用JDK 6中的新功能,...
**DOM4J学习笔记** DOM4J是一个Java库,它提供了强大的XML处理功能,包括解析、操作和生成XML文档。这个库是开源的,广泛应用于Java应用程序中,特别是在需要处理XML数据时。DOM4J的设计目标是易于使用,同时保持高...
**XSLT自动代码生成学习笔记** XSLT(Extensible Stylesheet Language Transformations)是一种强大的XML转换语言,常用于将XML数据转换成其他格式,如HTML、PDF或纯文本。在软件开发中,XSLT被广泛应用于自动代码...
### JSP学习笔记:重点知识点解析 #### 一、JSP简介 JSP(JavaServer Pages)是一种基于Java技术的动态网页技术标准。它通过在传统的HTML页面中嵌入Java代码来实现动态内容的生成。JSP页面最终会被转换成Servlet,...