网站首页/技术开发列表/内容

SAX编程基础

技术开发2024-04-11阅读
SAX编程入门

作者: 常明 写作日期:2000-4-26



SAX其实就是(Simple Application interface for XML),这个接口规范是XML分析器和XML处理器提供的较XML更底层的接口。它能提供应用以较大的灵活性。

SAX诞生是在XML-DEV讨论组上,提出它的原因是有一些情况不适用DOM接口,而且DOM实现太大而且比较慢。

SAX是一种事件驱动的接口,它的基本原理是,由接口的用户提供符合定义的处理器,XML分析时遇到特定的事件,就去调用处理器中特定事件的处理函数。一般SAX都是JAVA的接口,但其实C++也可以用SAX接口,但C++的分析器比较少。

开发者主要关心的就是,如果我用一个SAX接口的XML分析器或处理器,我需要做些什么呢?那么,下面我们就看一下程序怎么写吧!

SAX需要用户提供一下几个处理器类的实现:

DocumentHandlerXML:文件事件的处理器;

DTDHandler:DTD中事件的处理器;

ErrorHandler:出错处理器。

写程序就是以下这么几步了:

首先需要从这几个类继承出自己的子类,
重载其中自己感兴趣的事件的处理方法。
向分析器,注册此处理器类,其实告诉分析器使用你的处理器。
启动分析器。
下面是我抓来的一个例子(既然有现成的,自己写好象比较浪费了:PP),这个例子中的PrettyPrint类就是一个继承DocumentHandler的实现类,大家可以看到PrettyPrint选择实现了开始元素、结束元素、字符数据、处理指令这样几个事件,最后的结果就是把以不同深度的缩进表示元素的层次的形式把XML输出。

值得注意的是,在处理函数的参数中包含了与此事件相关的重要信息,处理函数其实就是对这些数据的处理。比如开始元素事件的参数中就会有元素名,属性列表的信息。


void PrettyPrint::startElement(const XMLCh* constname AttributeList& attributes)
{
indent++; // A new element started, //it should be indented one
// level further than the current level
int i;
for(i = 0; i < indent; i++) outStrm << "\t";
outStrm << "<" << name;
unsigned int len = attributes.getLength();
for (unsigned int i = 0; i < len; i++)
{
outStrm << " " << attributes.getName(i) <<
"=\"" << attributes.getValue(i) <<
"\"";
}
outStrm << ">";
}

void PrettyPrint::endElement(const XMLCh* const name)
{ int i; for(i = 0; i < indent; i++)
outStrm << "\t"; outStrm << "</" <<
name << ">";
indent--;
}

void PrettyPrint::characters(const XMLCh* const chars, const unsigned int
length)
{
for (unsigned int index = 0; index < length; index++)
{
switch (chars[index])
{
 case chAmpersand : outStrm << "&"; break;
 case chOpenAngle : outStrm << "<"; break;
 case chCloseAngle: outStrm << ">"; break;
 case chDoubleQuote : outStrm << """; break;
 default: outStrm << chars[index];
break;
 }
}
}

void PrettyPrint::processingInstruction(const XMLCh* const target, const
XMLCh* const data)
{
int i; for(i = 0; i < indent; i++) outStrm << "\t";
outStrm << "<?" << target; if (data) outStrm
<< " " << data; outStrm << "?>\n";

}

看过这个例子,大家应该是比较清楚如何写SAX的处理器了。具体的SAX接口可以在你要用的分析器的定义中找到,JAVA中就是interface或class,C++中可能就是类的定义。写好以后就要调用Parser类的以下函数,将处理器设到parser内去:

public abstract void setDTDHandler (DTDHandler handler);
public abstract void setDocumentHandler (DocumentHandler handler);

public abstract void setErrorHandler (ErrorHandler handler);

...

此外SAX接口里有另外的几个由分析器回调的处理器,他们的用法下面一一讲一下:

InputSource:这个处理器的作用是控制XML文件的输入,这样输入就可以有更多种选择,可以来自文件系统,或Web服务器,甚至数据库。

EntityResolver:解析外部实体用,分析器通过它得到外部实体。

Locator:定位器,作用是分析器用来在文件中定位的。作用之一就是报错时能得到错误的位置。

这几个的详细用法,如果需要我以后会写文章讲细一些。

DOM也是XML的数据接口,读到这里,有些读者可能会问,SAX和DOM的关系是怎样的呢? Don Park的SAXDOM实现了从SAX接口实现DOM模型,从这样一个工具我们可以看出SAX是比DOM更低层的接 口,有了SAX,我们完全可以自己构造出DOM。DOM好用一些,为什么还要提出SAX呢?DOM模型的建立是分 析完整个XML文件后才能完成,对于某些特殊情况用DOM实现就不太现实,如XML文件特别大时,在内存建立 一棵它的DOM树是不可想象的,还有当对于动态生成的XML,还没有完成时,我们就需要知道里面有什么, 这时也不能用DOM。另外SAX运行很快,对于一些简单的任务,用它效率比较高。所以DOM和SAX各有千秋, 可以在开发中互补。


相关阅读