综述
可扩展标注语言(eXtensible Markup Language
XML)正被迅速的运用于业界
它已作为与平台
语言和协议无关的格式描述和交换数据的广泛应用标准
XML和它的辅助规范可用于描述数据的文档表现
描述XML文档类型的限制
描述XML文档和资源之间的链接
描述XML文档的自动转换和格式化
如何开发自定义标签库?
我使用JSP和ASP编程已经有一段颇长的时间了在两种服务器端的编程方式中我越来越觉得JSP的功能要强大得多不提别的其中JSP的标签库就是我选择JSP作为首选服务器端Web应用开发工具的原因为什么?因为维护和开发的速度在一个单一的服务器页面中你可以混合使用各种不同的脚本方法和对象就?quot;混凝土一样这种混合可令服务器端的脚本变得强大并且让服务器端的编程者设计出非常灵活和动态的Web页面不过这种自由的混合也有其缺点那就是维护起来非常麻烦特别是当项目逐渐变大时由于最终的产品是经由一个传统的Web设计者来维护的因此会带来问题更糟糕的是随着代码的复杂性增加开发的速度就会变慢不利于开发中等和大型的Web应用一旦开发完站点还要找合格的编程者来维护这些颇为复杂的代码
幸好JSP提供了一个很好解决的办法标签库提供了一个简单的方法来建立一个可重用的代码块一旦标签库设计好它就可以在许多项目中再次使用更方便的是与COM和JEE不同你无需学习任何其它的技巧就可以建立一个标签库!只要你懂得写JSP你就可以建立一个标签库标签库还可以改善Web应用的维护这个是得益于JSP页面自定义标签的简单XML接口这样Web设计者甚至可以做到无需知道任何JSP的知识就可以建立JSP的Web应用这个开放式的Web开发对于团队运作是非常有效的JSP编程者可以建立自定义的标签和后台的代码模块而Web设计者可以使用自定义的标签来建立Web应用并且将精力集中在Web设计上
标签库的定义
JSP标签库(也称自定义库)可看成是一套产生基于XML脚本的方法它经由JavaBeans来支持在概念上说标签库是非常简单和可以重用的代码构造
执行XML/XSL转换的标签范例和HTML页面
<%@ taglib uri=/jspkit/JAXP prefix=JAXP%>
c:/xml/examplexml
c:/xml/examplexsl
在这个例子中通过使用简单的标签来访问后台更为强大的代码一个XML被装载并且通过一个XSL文件来产生一个结果并发送给客户端全部通过使用一个简单的标签调用就做到了
自定义标签为在JSP项目中创建易于重用的代码打开了一扇大门你所需要的只是标签库和它的文档说明
标签的组件
虽然标签库非常易于使用不过要建立一个内里的设计来支持标签库是颇复杂的起码要比建立一个简单的JavaBean复杂这个复杂是来自于标签库是由几部分构成的不过你只需要知道Java和JSP的知识就够了
一个简单的标签由下面的元素构成
⑴ JavaBeans为了得到Java与生具来的面向对象的好处可重用的代码应该放到一个独立的代码容器中这些JavaBeans并不是标签库的一部分不过它是你的代码库用来执行相关任务的基本代码块
⑵ 标签处理这是标签库的真正核心一个标签处理器将引用它需要的任何资源(你的JavaBeans)和访问你的JSP页面的全部信息(pageContext对象)JSP页面也会将所有已经被设置的标签属性和JSP页面上的标签体中的内容传送给标签处理器在标签处理器处理完毕后它将发回输出到你的JSP页面进行处理
⑶ 标签库的描述(tld文件)这是一个简单的XML文件它记录着标签处理器的属性信息和位置JSP容器通过这个文件来得知从哪里及如何调用一个标签库
⑷ 网站的webxml文件这是你网站的初始化文件在这个文件中你定义了网站中用到的自定义标签以及哪个tld文件用来描述每个自定义的标签
⑸ 分发文件(一个WAR或者JAR文件)如果你想重用自定义标签的话你需要一个方法来将它由一个项目转移到另一个项目中将标签库打包为一个JAR文件是一个简单而且有效的方式
⑹ 在你的JSP文件中作标签库声明很简单如果要用到该标签的话只要在页面声明一下就可以其后你就可以在该JSP页面的任何地方使用它
看来要做的工作很多不过其实并不是很难它的要点并不在于编码而是在于如何将各部分正确地组织起来不过这样的分层是很重要的它可令标签的使用灵活和更容易转移更重要的是这些层的存在可让处理建立标签的工程通过一个JSP IDE(JSP的集成开发环境)自动完成期望将来的JSP IDE可自动完成创建一个自定义标签的大部分工作这样你只需要写代码和标签处理就可以了
注意一个标签处理仅定义一个自定义标签一个标签库是几个处理相同任务的标签处理器的集合
建立自己的标签
以下将一步一步地教你如何建立自定义的标签具体的例子是扩展JSP令它拥有自己的HTML编码功能这个功能将所有的<和>字符用HTML代码来代替它可以很容易地扩展为做其它的编码处理为了简化这个例子只解释了建立自定义标签的基本要素
⑴ 创建一个JavaBean
你代码中任何可重新使用的部分都应该放到一个JavaBean中这个很重要因为你要经常在项目的其它地方用到这些代码放在标签处理器中的任何代码在标签外都是不可以重新使用的因此将可重用的代码部分独立开来是很重要的在这个例子总为HTML编码的逻辑是常用的因此放到JavaBean中
⑵ HTML编码JavaBean
/* HTML_FormatJava */
public class HTML_Format extends Object implements JavaioSerializable {
/** 创建新的HTML_Format */
public HTML_Format() {}
/** 将一个字符串中所有的所有 < 和 > 字符用响应的HTML编码代替 */
public String HTML_Encode(String as_data)
{
int li_len = as_datalength();
/*string buffer的长度要比原来的字符串长*/
StringBuffer lsb_encode = new StringBuffer(li_len + (li_len/));
/* 循环替换全部的< 和 > 字符 */
for( int li_count = ; li_count < li_len ; li_count++)
{ String ls_next = StringvalueOf(as_datacharAt(li_count));
if (ls_nextequals(<)) ls_next = <;
if (ls_nextequals(>)) ls_next = >;
lsb_encodeappend( ls_next );
}
return( lsb_encodetoString() );
}
}
⑶ 创建一个标签处理器
标签处理器使用以下的代码
HTML编码标签处理器
import JavaioIOException;
import Javaxservletjsp*;
import Javaxservletjsptagext*;
public class HTML_FormatTag extends BodyTagSupport
{
/* } 在标签末将会调用这个函数 */
public int doEndTag() throws JspTagException
{
try
{ /* }得到标签中的文本 */
BodyContent l_tagbody = getBodyContent();
String ls_output = ;
/* }如果标签体有文本就处理它 */
if(l_tagbody != null)
{ HTML_Format l_format = new HTML_Format();
/* a} 将标签体的内容转换为一个字符串 */
String ls_html_text = l_tagbodygetString();
ls_output = l_formatHTML_Encode(ls_html_text);
}
/* }将结果写回到数据流中 */
pageContextgetOut()write(ls_outputtrim());
}
catch (IOException e)
{ throw new JspTagException(Tag Error: + etoString());
}
/* 让JSP继续处理以下页面的内容 */
return EVAL_PAGE;
}
}
这个处理很简单它包括有
o 读入标签开始和结束间的文本
o 调用html编码函数
o 返回结果到JSP页面
⑷ 创建一个标签描述器
需要描述自定义标签以让系统知道如何处理该描述文件的后缀为tld通常它的名字和标签处理器相同并存放在/WEBINF/目录
HTML编码标签描述器
<?xml version= encoding=UTF ?>
<!DOCTYPE taglib
PUBLIC //Sun Microsystems Inc//DTD JSP Tag Library //EN
jsptaglibrary__dtd>
<TAGLIB>
<TLIBVERSION></TLIBVERSION>
<JSPVERSION></JSPVERSION>
<SHORTNAME>HTML_FormatTag</SHORTNAME>
<URI></URI>
<INFO>HTML Encoding Tag </INFO>
<TAG>
<NAME>HTMLEncode</NAME>
<TAGCLASS>HTML_FormatTag</TAGCLASS>
<INFO>Encode HTML</INFO>
</TAG>
</TAGLIB>
⑸ 更新Web XML文件
现在可告诉JSP容器使用标签库为此要修改webxml文件具体说来是要在其中加入一个taglib的项目来注册该标签库最重要的是要为tag分配一个URIURI是一个唯一的引用只应用在该网站的这个特别的标签上使用全长的URL或者包名是一个好的习惯它可以确保唯一性因为该标签可以在不同的网站使用这个例子是简化了
修改webxml文件
<?xml version= encoding=ISO?>
<!DOCTYPE webapp
PUBLIC //Sun Microsystems Inc//DTD Web Application //EN
app_dtd>
<WEBAPP>
<TAGLIB>
<TAGLIBURI>
HTMLEncode
</TAGLIBURI>
<TAGLIBLOCATION>
/WEBINF/HTML_FormatTagtld
</TAGLIBLOCATION>
</TAGLIB>
</WEBAPP>
⑹ 使用新的标签
自定义的标签已经设置好可以用在一个JSP页面上要做到这一点只需在该页面使用taglib指示命令声明一下该标签就可以了该标签通过它唯一的URI被引用并且会被分配一个名字空间前缀前缀可以任意只要它不与其它的名字空间沖突便可
在一个JSP页面上使用HTML编码标签
<%@ taglib uri=HTMLEncode prefix=Examples %>
<PRE>
<?XML:NAMESPACE PREFIX = Examples /><Examples:HTMLEncode>
< Hello Simple sample >
</Examples:HTMLEncode>
</PRE>
范例代码的输出
< Hello Simple sample >
which displays as:
< Hello Simple sample >
通过这个标签我就将该页面的所有代码编码了有趣的是所有的自定义标签都是在服务器上处理的这意味着你将不会在输出的页面上看到自定义的标签
建立一个标签不是很难吧最困难的部分是要学习标签处理的所有细节这是一个很强大的功能我们只是提到了最基本的地方由于这个处理需要几步新的JSP编程者在创建标签时将会感到迷惑
如何利用JSP开发DOM应用?DOM是Document Object Model的缩写即文档对象模型XML将数据组织为一颗树所以DOM就是对这颗树的一个对象描叙通俗的说就是通过解析XML文档为XML文档在逻辑上建立一个树模型树的节点是一个个对象我们通过存取这些对象就能够存取XML文档的内容
下面我们来看一个简单的例子看看在DOM中我们是如何来操作一个XML文档的这是一个XML文档也是我们要操作的对象
<?xml version= encoding=UTF?>
<messages>
<message>Goodbye serialization hello Java!</message>
</messages>
下面我们需要把这个文档的内容解析到一个个的Java对象中去供程序使用利用JAXP我们只需几行代码就能做到这一点首先我们需要建立一个解析器工厂以利用这个工厂来获得一个具体的解析器对象
DocumentBuilderFactory dbf = DocumentBuilderFactorynewInstance();
我们在这里使用DocumentBuilderFacotry的目的是为了创建与具体解析器无关的程序当DocumentBuilderFactory类的静态方法newInstance()被调用时它根据一个系统变量来决定具体使用哪一个解析器又因为所有的解析器都服从于JAXP所定义的接口所以无论具体使用哪一个解析器代码都是一样的所以当在不同的解析器之间进行切换时只需要更改系统变量的值而不用更改任何代码这就是工厂所带来的好处
DocumentBuilder db = dbfnewDocumentBuilder();
当获得一个工厂对象后使用它的静态方法newDocumentBuilder()方法可以获得一个DocumentBuilder对象这个对象代表了具体的DOM解析器但具体是哪一种解析器微软的或者IBM的对于程序而言并不重要
然后我们就可以利用这个解析器来对XML文档进行解析了
Document doc = dbparse(c:/xml/messagexml);
DocumentBuilder的parse()方法接受一个XML文档名作为输入参数返回一个Document对象这个Document对象就代表了一个XML文档的树模型以后所有的对XML文档的操作都与解析器无关直接在这个Document对象上进行操作就可以了而具体对Document操作的方法就是由DOM所定义的了
从得到的Document对象开始我们就可以开始我们的DOM之旅了使用Document对象的getElementsByTagName()方法我们可以得到一个NodeList对象一个Node对象代表了一个XML文档中的一个标签元素而NodeList对象观其名而知其意所代表的是一个Node对象的列表
NodeList nl = docgetElementsByTagName(message);
我们通过这样一条语句所得到的是XML文档中所有<message>标签对应的Node对象的
一个列表然后我们可以使用NodeList对象的item()方法来得到列表中的每一个Node对象
Node my_node = em();
当一个Node对象被建立之后保存在XML文档中的数据就被提取出来并封装在这个Node中了在这个例子中要提取Message标签内的内容我们通常会使用Node对象的getNodeValue()方法
String message = my_nodegetFirstChild()getNodeValue();
请注意这里还使用了一个getFirstChild()方法来获得message下面的第一个子Node对象虽然在message标签下面除了文本外并没有其它子标签或者属性但是我们坚持在这里使用getFirseChild()方法这主要和WC对DOM的定义有关WC把标签内的文本部分也定义成一个Node所以先要得到代表文本的那个Node我们才能够使用getNodeValue()来获取文本的内容现在既然我们已经能够从XML文件中提取出数据了我们就可以把这些数据用在合适的地方来构筑应用程序
DOM实例
先说说这个例子到底要做的是什么吧我们在一个名为linkxml文件中保存了一些URL地址我们希望可以通过DOM把这些URL读出并显示出来也可以反过来向这个XML文件中写入加入的URL地址很简单却很实用也足够来例示DOM的绝大部分用法了
第一个程序我们称为xmldisplayJava主要的功能就是读取这个XML文件中各个节点的内容然后在格式化输出在Systemout上我们来看看这个程序
import Javaxxmlparsers*;
import orgwcdom*;
这是引入必要的类因为在这里使用的是Sun所提供的XML解析器因而需要引入Javaxmlparsers包其中包含了有DOM解析器和SAX解析器的具体实现orgwcdom包中定义了wc所制定的DOM接口
DocumentBuilderFactory factory = DocumentBuilderFactorynewInstance();
DocumentBuilder builder=factorynewDocumentBuilder();
Document doc=builderparse(linksxml);
docnormalize();
除了上面讲到的还有一个小技巧对Document对象调用normalize()可以去掉XML文档中作为格式化内容的空白而映射在DOM树中的不必要的Text Node对象否则你得到的DOM树可能并不如你所想象的那样特别是在输出的时候这个normalize()更为有用
NodeList links =docgetElementsByTagName(link);
刚才说过XML文档中的空白符也会被作为对象映射在DOM树中因而直接调用Node方法的getChildNodes方法有时候会有些问题有时不能够返回所期望的NodeList对象解决的办法是使用Element的getElementByTagName(String)返回的NodeLise就是所期待的对象了然后可以用item()方法提取想要的元素
for (int i=;i<linksgetLength();i++){
Element link=(Element) em(i);
Systemoutprint(Content: );
Systemoutprintln(linkgetElementsByTagName(textem()getFirstChild();
getNodeValue());
……
上面的代码片断就完成了对XML文档内容的格式化输出只要注意到一些细节的问题比如getFirstChile()方法和getElementsByTagName()方法的使用这些还是比较容易的
下面的内容就是在修改了DOM树后重新写入到XML文档中去的问题了这个程序名为xmlwriteJava在JAXP版本中并没有直接的类和方法能够处理XML文档的写入问题需要借助其它包中的一些辅助类而在JAXP版本中引入了对XSLT的支持所谓XSLT就是对XML文档进行变换(Translation)后得到一个新的文档结构利用这个新加入的功能我们就能够很方便的把新生成或者修改后的DOM树从新写回到XML文件中去了下面我们来看看代码的实现这段代码的主要功能是向linksxml文件中加入一个新的link节点
import Javaxxmlparsers*;
import Javaxxmltransform*;
import JavaxxmltransformdomDOMSource;
import JavaxxmltransformstreamStreamResult;
import orgwcdom*;
新引入的Javaxmltransform包中的几个类就是用来处理XSLT变换的
我们希望在上面的XML文件中加入一个新的link节点因而首先还是要读入linksxml文件构建一个DOM树然后再对这个DOM树进行修改(添加节点)最后把修改后的DOM写回到linksxml文件中
DocumentBuilderFactory factory = DocumentBuilderFactorynewInstance();
DocumentBuilder builder=factorynewDocumentBuilder();
Document doc=builderparse(linksxml);
docnormalize();
//取得变量
String text=Hanzhongs Homepage;
String url=;
String author=Hzliu Liu;
String discription=A site from Hanzhong Liu give u lots of suprise!!!;
为了看清重点简化程序我们把要加入的内容硬编码到记忆String对象中而实际操作中往往利用一个界面来提取用户输入或者通过JDBC从数据库中提取想要的内容
Text textseg;
Element link=doccreateElement(link);
首先应该明了的是无论什么类型的NodeText型的也好Attr型的也好Element型的也好它们的创建都是通过Document对象中的createXXX()方法来创建的(XXX代表具体要创建的类型)因此我们要向XML文档中添加一个link项目首先要创建一个link对象
Element linktext=doccreateElement(text);
textseg=doccreateTextNode(text);
linktextappendChild(textseg);
linkappendChild(linktext);
……
创建节点的过程可能有些千篇一律但需要注意的地方是对Element中所包含的text(在DOM中这些text也是代表了一个Node的因此也必须为它们创建相应的node)不能直接用Element对象的setNodeValue()方法来设置这些text的内容而需要用创建的Text对象的setNodeValue()方法来设置文本这样才能够把创建的Element和其文本内容添加到DOM树中看看前面的代码你会更好的理解这一点
docgetDocumentElement()appendChild(link);
最后不要忘记把创建好的节点添加到DOM树中Document类的getDocumentElement()方法返回代表文档根节点的Element对象在XML文档中根节点一定是唯一的
TransformerFactory tFactory =TransformerFactorynewInstance();
Transformer transformer = tFactorynewTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new JavaioFile(linksxml));
transformertransform(source result);
然后就是用XSLT把DOM树输出了这里的TransformerFactory也同样应用了工厂模式使得具体的代码同具体的变换器无关实现的方法和DocumentBuilderFactory相同这儿就不赘述了Transformer类的transfrom方法接受两个参数一个数据源Source和一个输出目标Result这里分别使用的是DOMSource和StreamResult这样就能够把DOM的内容输出到一个输出流中当这个输出流是一个文件的时候DOM的内容就被写入到文件中去了
如何利用JSP开发SAX应用?SAX是Simple API for XML的缩写它并不是由WC官方所提出的标准可以说是民间的事实标准实际上它是一种社区性质的讨论产物虽然如此在XML中对SAX的应用丝毫不比DOM少几乎所有的XML解析器都会支持它
与DOM比较而言SAX是一种轻量型的方法我们知道在处理DOM的时候我们需要读入整个的XML文档然后在内存中创建DOM树生成DOM树上的每个Node对象当文档比较小的时候这不会造成什么问题但是一旦文档大起来处理DOM就会变得相当费时费力特别是其对于内存的需求也将是成倍的增长以至于在某些应用中使用DOM是一件很不划算的事(比如在applet中)这时候一个较好的替代解决方法就是SAX
SAX在概念上与DOM完全不同首先不同于DOM的文档驱动它是事件驱动的也就是说它并不需要读入整个文档而文档的读入过程也就是SAX的解析过程所谓事件驱动是指一种基于回调(callback)机制的程序运行方法(如果你对Java新的代理事件模型比较清楚的话就会很容易理解这种机制了)在XMLReader接受XML文档在读入XML文档的过程中就进行解析也就是说读入文档的过程和解析的过程是同时进行的这和DOM区别很大解析开始之前需要向XMLReader注册一个ContentHandler也就是相当于一个事件监听器在ContentHandler中定义了很多方法比如startDocument()它定制了当在解析过程中遇到文档开始时应该处理的事情当XMLReader读到合适的内容就会抛出相应的事件并把这个事件的处理权代理给ContentHandler调用其相应的方法进行响应
这样泛泛的说来或许有些不容易理解别急后面的例子会让你明白SAX的解析过程看看这个简单XML文件
<POEM>
<AUTHOR>Ogden Nash</AUTHOR>
<TITLE>Fleas</TITLE>
<LINE>Adam</LINE>
</POEM>
当XMLReader读到<POEM>标签时就会调用ContentHandlerstartElement()方法并把标签名POEM作为参数传递过去在你实现的startElement()方法中需要做相应的动作以处理当<POEM>出现时应该做的事情各个事件随着解析的过程(也就是文档读入的过程)一个个顺序的被抛出相应的方法也会被顺序的调用最后当解析完成方法都被调用后对文档的处理也就完成了下面的这个表列出了在解析上面的那个XML文件的时候顺序被调用的方法
遇到的项目 方法回调
{文档开始} startDocument()
<POEM> startElement(nullPOEMnull{Attributes})
\n characters(<POEM>\n )
<AUTHOR> startElement(nullAUTHORnull{Attributes})
Ogden Nash characters(<POEM>\n )
</AUTHOR> endElement(nullAUTHORnull)
\n characters(<POEM>\n )
<TITLE> startElement(nullTITLEnull{Attributes})
Fleas characters(<POEM>\n )
</TITLE> endElement(nullTITLEnull)
\n characters(<POEM>\n )
<LINE> startElement(nullLINEnull{Attributes})
Adam characters(<POEM>\n )
</LINE> endElement(nullLINEnull)
\n characters(<POEM>\n )
</POEM> endElement(nullPOEMnull)
{文档结束} endDocument()
ContentHandler实际上是一个接口当处理特定的XML文件的时候就需要为其创建一个实现了ContentHandler的类来处理特定的事件可以说这个实际上就是SAX处理XML文件的核心下面我们来看看定义在其中的一些方法
void characters(char[] ch int start int length)这个方法用来处理在XML文件中读到字符串它的参数是一个字符数组以及读到的这个字符串在这个数组中的起始位置和长度我们可以很容易的用String类的一个构造方法来获得这个字符串的String类String charEncontered=new String(chstartlength)
void startDocument()当遇到文档的开头的时候调用这个方法可以在其中做一些预处理的工作
void endDocument()和上面的方法相对应当文档结束的时候调用这个方法可以在其中做一些善后的工作
void startElement(String namespaceURI String localName String qName Attributes atts)当读到一个开始标签的时候会触发这个方法在SAX版本中并不支持名域而在新的版本中提供了对名域的支持这儿参数中的namespaceURI就是名域localName是标签名qName是标签的修饰前缀当没有使用名域的时候这两个参数都未null而atts是这个标签所包含的属性列表通过atts可以得到所有的属性名和相应的值要注意的是SAX中一个重要的特点就是它的流式处理在遇到一个标签的时候它并不会纪录下以前所碰到的标签也就是说在startElement()方法中所有你所知道的信息就是标签的名字和属性至于标签的嵌套结构上层标签的名字是否有子元属等等其它与结构相关的信息都是不得而知的都需要你的程序来完成这使得SAX在编程处理上没有DOM来得那么方便
void endElement(String namespaceURI String localName String qName)这个方法和上面的方法相对应在遇到结束标签的时候调用这个方法
我们还是沿用讲DOM的时候使用的那个文档例子但首先我们先看一个简单一些的应用我们希望能够统计一下XML文件中各个标签出现的次数这个例子很简单但是足以阐述SAX编程的基本思路了一开始当然还是import语句了
import orgxmlsaxhelpersDefaultHandler;
import Javaxxmlparsers*;
import orgxmlsax*;
import orgxmlsaxhelpers*;
import Javautil*;
import Javaio*;
然后我们创建一个继承于DefaultHandler的类具体的程序逻辑在这儿可以暂且放在一边要注意的是程序的结构
public class SAXCounter extends DefaultHandler {
private Hashtable tags; //这个Hashtable用来记录tag出现的次数
// 处理文档前的工作
public void startDocument() throws SAXException {
tags = new Hashtable();//初始化Hashtable
}
//对每一个开始元属进行处理
public void startElement(String namespaceURI String localName
String rawName Attributes atts)
throws SAXException
{
String key = localName;
……
我们来看看这段程序作了些什么在main()方法中主要做的就是创建解析器然后解析文档实际上在这儿创建SAXParser对象的时候为了使程序代码于具体的解析器无关使用了同DOM中一样的设计技巧通过一个SAXParserFactory类来创建具体的SAXParser对象这样当需要使用不同的解析器的时候要改变的只是一个环境变量的值而程序的代码可以保持不变这就是FactoryMethod模式的思想在这儿不再具体讲了如果还有不明白的可以参看上面DOM中的解释原理是一样的
不过在这儿还有一点点要注意的地方就是SAXParser类和XMLReader类之间的关系你可能有些迷糊了吧实际上SAXParser是JAXP中对XMLReader的一个封装类而XMLReader是定义在SAX种的一个用来解析文档的接口你可以同样的调用SAXParser或者XMLReader中的parser()方法来解析文档效果是完全一样的不过在SAXParser中的parser()方法接受更多的参数可以对不同的XML文档数据源进行解析因而使用起来要比XMLReader要方便一些
这个例子仅仅涉及了SAX的一点皮毛而下面的这个可就要高级一些了下面我们要实现的功能在DOM的例子中已经有实现了就是从XML文档中读出内容并格式化输出虽然程序逻辑看起来还是很简单但是SAX可不比DOM哦看着吧
前面说过当遇到一个开始标签的时候在startElement()方法中我们并不能够得到这个标签在XML文档中所处的位置这在处理XML文档的时候是个大麻烦因为在XML中标签的语义有一部分是由其所处的位置所决定的而且在一些需要验证文档结构的程序中这更是一个问题当然没有解决不了的问题了我们可以使用一个栈来实现对文档结构的纪录
栈的特点是先进先出我们现在的想法是在startElemnt()方法中用push将这个标签的名字添加到栈中在endElement()方法中在把它pop出来我们知道对一个结构良好的XML而言其嵌套结构是完备的每一个开始标签总会对应一个结束标签而且不会出现标签嵌套之间的错位因而每一次startElement()方法的调用必然会对应一个endElement()方法的调用这样push和pop也是成对出现的我们只需要分析栈的结构就可以很容易的知道当前标签所处在文档结构中的位置了
public class SAXReader extends DefaultHandler {
JavautilStack tags=new JavautilStack();
……
在这儿虽然没有使用到栈的分析但实际上栈的分析是一件很容易的事情应为JavautilStack继承了JavautilVector类而且Stack中的元素是按栈的结构由底至上排列的因个我们可以使用Vector类的size()方法来得到Stack的元素个数还可以使用Vector的get(int)方法来得到具体的每一个元属实际上如果把Stack的元素从底向上逐一排列出来我们就得到了从XML根节点到当前节点的一条唯一的路径有了这条路径的信息文档的结构就在清楚不过了
到目前为止我们已经掌握了对于XML编程的两大利器DOM和SAX也知道了该如何在一个Java程序中使用它们DOM编程相对简单但是速度比较慢占用内存多而S AX编程复杂一些但是速度快占用内存少所以我们应该根据不同的环境选择使用不同的方法大部分的XML应用基本都可以用它们来解决需要特别说明的是DOM和SAX其实都是语言无关的并非Java所独有也就是说只要有相应的语言实现DOM和SAX可以应用在任何面向对象的语言中