|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
Java编译的是字节码,跟C++相反,启动不够快,效率不够高,难以精确控制内存,但是优点是编程比C++容易,代码比较安全但是容易留下性能隐患,跨平台靠字节码在各个平台复制(一处编译到处调试)xml|编程SAX观点
SAX是SimpleAPIforXML的缩写,它并非由W3C官方所提出的尺度,能够说是“官方”的现实尺度。实践上,它是一种社区性子的会商产品。固然云云,在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>OgdenNash</AUTHOR>
<TITLE>Fleas</TITLE>
<LINE>Adam</LINE>
</POEM>
当XMLReader读到<POEM>标签时,就会挪用ContentHandler.startElement()办法,并把标署名POEM作为参数传送已往。在你完成的startElement()办法中必要做响应的举措,以处置当<POEM>呈现时应当做的事变。各个事务跟着剖析的历程(也就是文档读进的历程)一个个按次的被抛出,响应的办法也会被按次的挪用,最初,当剖析完成,办法都被挪用后,对文档的处置也就完成了。上面的这个表,列出了在剖析下面的谁人XML文件的时分,按次被挪用的办法:
ContentHandler实践上是一个接口,当处置特定的XML文件的时分,就必要为其创立一个完成了ContentHandler的类来处置特定的事务,能够说,这个实践上就是SAX处置XML文件的中心。上面我们来看看界说在个中的一些办法:
voidcharacters(char[]ch,intstart,intlength):
这个办法用来处置在XML文件中读到字符串,它的参数是一个字符数组,和读到的这个字符串在这个数组中的肇端地位和长度,我们能够很简单的用String类的一个机关办法来取得这个字符串的String类:StringcharEncontered=newString(ch,start,length)。
voidstartDocument():
当碰到文档的开首的时分,挪用这个办法,能够在个中做一些预处置的事情。
voidendDocument():
和下面的办法绝对应,当文档停止的时分,挪用这个办法,能够在个中做一些善后的事情。
voidstartElement(java.lang.StringnamespaceURI,java.lang.StringlocalName,java.lang.StringqName,Attributesatts)
当读到一个入手下手标签的时分,会触发这个办法。在SAX1.0版本中其实不撑持名域,而在新的2.0版本中供应了对名域的撑持,这儿参数中的namespaceURI就是名域,localName是标署名,qName是标签的润色前缀,当没有利用名域的时分,这两个参数都未null。而atts是这个标签所包括的属性列表。经由过程atts,能够失掉一切的属性名和响应的值。要注重的是SAX中一个主要的特性就是它的流式处置,在碰到一个标签的时分,它其实不会记录下之前所碰着的标签,也就是说,在startElement()办法中,一切你所晓得的信息,就是标签的名字和属性,至于标签的嵌套布局,下层标签的名字,是不是有子元属等等别的与布局相干的信息,都是不得而知的,都必要你的程序来完成。这使得SAX在编程处置上没有DOM来得那末便利。
voidendElement(java.lang.StringnamespaceURI,java.lang.StringlocalName,java.lang.StringqName)
这个办法和下面的办法绝对应,在碰到停止标签的时分,挪用这个办法。
由于ContentHandler是一个接口,在利用的时分大概会有些不便利,因此,SAX中还为其制订了一个Helper类:DefaultHandler,它完成了这个接口,可是其一切的办法体都为空,在完成的时分,你只必要承继这个类,然后重载响应的办法便可。
OK,到这儿SAX的基础常识已差未几讲完了,上面我们来看看两个详细的例子,以更好的了解SAX地用法。
SAX编程实例
我们仍是相沿讲DOM的时分利用的谁人文档例子,但起首,我们先看一个复杂一些的使用,我们但愿可以统计一下XML文件中各个标签呈现的次数。这个例子很复杂,可是足以论述SAX编程的基础思绪了。
一入手下手固然仍是import语句了:
importorg.xml.sax.helpers.DefaultHandler;
importjavax.xml.parsers.*;
importorg.xml.sax.*;
importorg.xml.sax.helpers.*;
importjava.util.*;
importjava.io.*;
然后,我们创立一个承继于DefaultHandler的类,详细的程序逻辑在这儿能够临时放在一边,要注重的是程序的布局:
publicclassSAXCounterextendsDefaultHandler{
privateHashtabletags;//这个Hashtable用来纪录tag呈现的次数
//处置文档前的事情
publicvoidstartDocument()throwsSAXException{
tags=newHashtable();//初始化Hashtable
}
//对每个入手下手元属举行处置
publicvoidstartElement(StringnamespaceURI,StringlocalName,
StringrawName,Attributesatts)
throwsSAXException
{
Stringkey=localName;
Objectvalue=tags.get(key);
if(value==null){
//假如是新碰着的标签,这在Hastable中增加一笔记录
tags.put(key,newInteger(1));
}else{
//假如之前碰着过,失掉其计数值,并加1
intcount=((Integer)value).intValue();
count++;
tags.put(key,newInteger(count));
}
}
//剖析完成后的统计事情
publicvoidendDocument()throwsSAXException{
Enumeratione=tags.keys();
while(e.hasMoreElements()){
Stringtag=(String)e.nextElement();
intcount=((Integer)tags.get(tag)).intValue();
System.out.println("Tag<"+tag+">occurs"+count
+"times");
}
}
//程序出口,用来完成剖析事情
staticpublicvoidmain(String[]args){
Stringfilename=null;
booleanvalidation=false;
filename="links.xml";
SAXParserFactoryspf=SAXParserFactory.newInstance();
XMLReaderxmlReader=null;
SAXParsersaxParser=null;
try{
//创立一个剖析器SAXParser对象
saxParser=spf.newSAXParser();
//失掉SAXParser中封装的SAXXMLReader
xmlReader=saxParser.getXMLReader();
}catch(Exceptionex){
System.err.println(ex);
System.exit(1);
}
try{
//利用指定的ContentHandler,剖析给XML文件,这儿要注重的是,为了
//程序的复杂起见,这儿将主程序和ContentHandler放在了一同。实践上
//main办法中所作的一切事变,都与ContentHandler有关。
xmlReader.parse(newFile(filename),newSAXCounter());
}catch(SAXExceptionse){
System.err.println(se.getMessage());
System.exit(1);
}catch(IOExceptionioe){
System.err.println(ioe);
System.exit(1);
}
}
}
我们来看看这段程序作了些甚么,在main()办法中,次要做的就是创立剖析器,然后剖析文档。实践上,在这儿创立SAXParser对象的时分,为了使程序代码于详细的剖析器有关,利用了同DOM中一样的计划技能:经由过程一个SAXParserFactory类来创立详细的SAXParser对象,如许,当必要利用分歧的剖析器的时分,要改动的,只是一个情况变量的值,而程序的代码能够坚持稳定。这就是FactoryMethod形式的头脑。在这儿不再详细讲了,假如另有不分明的,能够参看下面DOM中的注释,道理是一样的。
不外在这儿另有一点点要注重的中央,就是SAXParser类和XMLReader类之间的干系。你大概有些含混了吧,实践上SAXParser是JAXP中对XMLReader的一个封装类,而XMLReader是界说在SAX2.0种的一个用来剖析文档的接口。你能够一样的挪用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也是成对呈现的,我们只必要剖析栈的布局,就能够很简单的晓得以后标签所处在文档布局中的地位了。
publicclassSAXReaderextendsDefaultHandler{
java.util.Stacktags=newjava.util.Stack();
//--------------XMLContent-------------
Stringtext=null;
Stringurl=null;
Stringauthor=null;
Stringdescription=null;
Stringday=null;
Stringyear=null;
Stringmonth=null;
//----------------------------------------------
publicvoidendDocument()throwsSAXException{
System.out.println("------ParseEnd--------");
}
publicvoidstartDocument()throwsSAXException{
System.out.println("------ParseBegin--------");
}
publicvoidstartElement(Stringp0,Stringp1,Stringp2,Attributesp3)throwsSAXException{
tags.push(p1);
}
publicvoidendElement(Stringp0,Stringp1,Stringp2)throwsSAXException{
tags.pop();
//一个link节点的信息搜集齐了,将其格局化输入
if(p1.equals("link"))printout();
}
publicvoidcharacters(char[]p0,intp1,intp2)throwsSAXException{
//从栈中失掉以后节点的信息
Stringtag=(String)tags.peek();
if(tag.equals("text"))text=newString(p0,p1,p2);
elseif(tag.equals("url"))url=newString(p0,p1,p2);
elseif(tag.equals("author"))author=newString(p0,p1,p2);
elseif(tag.equals("day"))day=newString(p0,p1,p2);
elseif(tag.equals("month"))month=newString(p0,p1,p2);
elseif(tag.equals("year"))year=newString(p0,p1,p2);
elseif(tag.equals("description"))year=newString(p0,p1,p2);
}
privatevoidprintout(){
System.out.print("Content:");
System.out.println(text);
System.out.print("URL:");
System.out.println(url);
System.out.print("Author:");
System.out.println(author);
System.out.print("Date:");
System.out.println(day+"-"+month+"-"+year);
System.out.print("Description:");
System.out.println(description);
System.out.println();
}
staticpublicvoidmain(String[]args){
Stringfilename=null;
booleanvalidation=false;
filename="links.xml";
SAXParserFactoryspf=SAXParserFactory.newInstance();
SAXParsersaxParser=null;
try{
saxParser=spf.newSAXParser();
}catch(Exceptionex){
System.err.println(ex);
System.exit(1);
}
try{
saxParser.parse(newFile(filename),newSAXReader());
}catch(SAXExceptionse){
System.err.println(se.getMessage());
System.exit(1);
}catch(IOExceptionioe){
System.err.println(ioe);
System.exit(1);
}
}
}
在这儿固然没有利用到栈的剖析,但实践上栈的剖析是一件很简单的事变,应为java.util.Stack承继了java.util.Vector类,并且Stack中的元素是按栈的布局由底至上分列的,因个,我们可使用Vector类的size()办法来失掉Stack的元素个数,还可使用Vector的get(int)办法来失掉详细的每个元属。实践上,假如把Stack的元素从底向上一一分列出来,我们就失掉了从XML根节点到以后节点的一条独一的路径,有了这条路径的信息,文档的布局就在分明不外了。
大节
好了,到这儿为止,我们已把握了关于XML编程的两年夜利器:DOM和SAX,也晓得了该怎样在一个Java程序中利用它们。DOM编程绝对复杂,可是速率对照慢,占用内存多,而SAX编程庞大一些,可是速率快,占用内存少。以是,我们应当依据分歧的情况选择利用分歧的办法。年夜部分的XML使用基础都能够用它们来办理。必要出格申明的是,DOM和SAX实在都是言语有关的,并不是Java所独占,也就是说,只需有响应的言语完成,DOM和SAX能够使用在任何面向对象的言语中。
下面我们先容了XML文档的读进,内容提取,和文档增加和修正的一些办法。另有一类的成绩就是XML文档的转换,固然用DOM和SAX也能够办理,可是完成起来很庞大,而使用XSLT就会复杂很多。这个成绩,笔者将会在今后的文章中再和人人具体会商
先谈谈我对java的一些认识。我选择java,是因为他语法简单,功能强大,从web,到桌面,到嵌入式,无所不能。但当我进一步了解了java后,感叹,java原来也有许多缺点。 |
|