学习笔记-理解sax

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 社区事实上的标准。
[list]
[*]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 来完成这个任务!
[/list]
使用样例

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();


如果不能获取信息,可尝试设置解析器的这些特性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值