例一:
package simpleTest;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.Locator;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;
import java.io.IOException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
class TestSAX extends DefaultHandler
{
private StringBuffer buf;
public TestSAX()
{
super();
}
public void setDocumentLocator(Locator locator)
{
}
public void startDocument() throws SAXException
{
buf=new StringBuffer();
System.out.println("*******開始解析文檔*******");
}
public void endDocument() throws SAXException
{
System.out.println("*******文檔解析結(jié)束*******");
}
public void startPrefixMapping( String prefix, String uri )
{
System.out.println(" 前綴映射: " + prefix +" 開始!"+ " 它的URI是:" + uri);
}
public void endPrefixMapping( String prefix )
{
System.out.println(" 前綴映射: "+prefix+" 結(jié)束!");
}
public void processingInstruction( String target, String instruction )
throws SAXException
{
}
public void ignorableWhitespace( char[] chars, int start, int length ) throws SAXException
{
}
public void skippedEntity( String name ) throws SAXException
{
}
public void startElement(String namespaceURI,String localName,String qName,Attributes atts)
{
System.out.println("*******開始解析元素*******");
System.out.println("元素名"+qName);
for(int i=0;i<atts.getLength();i++)
{
System.out.println("元素名"+atts.getLocalName(i)+"屬性值"+atts.getValue(i));
}
}
public void endElement(String namespaceURI,String localName,String fullName )throws SAXException
{
System.out.println("******元素解析結(jié)束********");
}
public void characters( char[] chars, int start, int length )throws SAXException
{
//將元素內(nèi)容累加到StringBuffer中
buf.append(chars,start,length);
}
public static void main(String args[])
{
try{
SAXParserFactory sf = SAXParserFactory.newInstance();
SAXParser sp = sf.newSAXParser();
TestSAX testsax=new TestSAX();
sp.parse(new InputSource("D:\test\simpleTest\classes\simpleTest\test.xml"),testsax);
}catch(IOException e)
{
e.printStackTrace();
}catch(SAXException e)
{
e.printStackTrace();
}catch(Exception e)
{
e.printStackTrace();
}
}
}
XML文件如下:
<?xml version="1.0" encoding="gb2312"?>
<row>
<person>
<name>王小明</name>
<college>信息學(xué)院</college>
<telephone>6258113</telephone>
<notes>男,1955年生,博士,95年調(diào)入海南大學(xué)</notes>
</person>
</row>
例二:
XML文檔樣本:
<?xml version="1.0"?><simple date="7/7/2000" ><name> Bob </name><location> New York </location></simple>
代碼:
package xmltest;import javax.xml.parsers.*;import org.xml.sax.*;import org.xml.sax.helpers.*;import java.io.*;public class SaxTest extends DefaultHandler {// 重載DefaultHandler類的方法// 以攔截SAX事件通知。//// 關(guān)于所有有效事件,見org.xml.sax.ContentHandler//public void startDocument( ) throws SAXException {System.out.println( "SAX Event: START DOCUMENT" );}public void endDocument( ) throws SAXException {System.out.println( "SAX Event: END DOCUMENT" );}public void startElement( String namespaceURI,String localName,String qName,Attributes attr ) throws SAXException {System.out.println( "SAX Event: START ELEMENT[ " +localName + " ]" );// 如果有屬性,我們也一并打印出來...for ( int i = 0; i < attr.getLength(); i++ ){System.out.println( " ATTRIBUTE: " +attr.getLocalName(i) +" VALUE: " +attr.getValue(i) );}}public void endElement( String namespaceURI,String localName,String qName ) throws SAXException {System.out.println( "SAX Event: END ELEMENT[ " +localName + " ]" );}public void characters( char[] ch, int start, int length )throws SAXException {System.out.print( "SAX Event: CHARACTERS[ " );try {OutputStreamWriter outw = new OutputStreamWriter(System.out);outw.write( ch, start,length );outw.flush();} catch (Exception e) {e.printStackTrace();}System.out.println( " )" );}public static void main( String[] argv ){System.out.println( "Example1 SAX Events:" );try {// SAXParserFactory spFactory = SAXParserFactory.newInstance();// SAXParser sParser = spFactory.newSAXParser();// 建立SAX 2解析器...XMLReader xr = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");// 安裝ContentHandler...xr.setContentHandler( new SaxTest() );// 解析文件...xr.parse( new InputSource(new FileReader( "exampleA.xml" )) );}catch ( Exception e ) {e.printStackTrace();}}}
當(dāng)前SAX API有兩個版本。第二版中的類名和方法名與第一版都有出入,但是代碼的結(jié)構(gòu)是一樣的。
SAX是一套API,它不是一個解析器,所以這個代碼在XML解析器中是通用的。要讓示例跑起來,你將需要一個支持SAX v2的XML解析器。我用Apache的Xerces解析器.代碼如下
// 建立SAX 2解析器...
XMLReader xr = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
// 安裝ContentHandler...
xr.setContentHandler( new SaxTest() );
SAX API 的說明書通俗易讀。它包含了很多的詳細內(nèi)容。而使用SAX API的主要任務(wù)就是創(chuàng)建一個實現(xiàn)ContentHandler接口,一個供XML 解析器調(diào)用以將分析XML文檔時所發(fā)生的SAX事件分發(fā)給處理程序的回調(diào)接口。
方便起見,SAX API也提供了一個已經(jīng)實現(xiàn)了ContentHandler接口的DefaultHandler適配器類。
一但實現(xiàn)了ContentHandler或者擴展了DefaultHandler類,你只需直接將XML解析器解析一個特定的文檔即可。
我們的第一個例子擴展DefaultHandler將每個SAX事件打印到控制臺。這將給你一個初步的映象,以說明什么SAX事件將會發(fā)生及以怎樣的順序發(fā)生。
下面介紹一下其它操作XML的API
stax(simple stream api for xml)作為jsr已經(jīng)出現(xiàn)幾年時間了,可能不如sax,dom(及其他基于其上的工具包比如jdom,jaxp,etc)為眾人所知??赡芤彩且驗樽罱黿fire的火熱 導(dǎo)致它的知名度有所提升吧。(題 外話,好象有不少知識點一直都是默默無聞的,只有隨著某項技術(shù)的流行才突然變的為人所知道了,比如ThreadLocal本來我們一直沒有接觸,很多人可能一直都不知道它的存在,但隨著它在spring ,hibernate這些流行的技術(shù)里的靈巧的應(yīng)用,一下子就被很多人談及及應(yīng)用了??梢娢覀兊乃竭€是屬于跟在老外屁股后面跑的水平)。
通過和dom,sax這兩種大家熟知的xml解析方式的比較,可以容易的看出它的特點。
dom通過把整個tree 文檔讀入內(nèi)存進行操作,可以隨意對文檔進行操作,非常靈活。但缺點是對內(nèi)存的資源耗費比較大。
sax不同于dom把整個文檔讀入內(nèi)存的方式,它是直接對 xml文件進行操作。速度快,基本上不占用什么內(nèi)存資源。缺點看看它的名字就知道了(simple api for xml),基于event的方式(這點和stax類似),但是是通過callback的方式把對xml的遍歷權(quán)交給sax parser了。這樣導(dǎo)致我們不能靈活控制對xml文件的訪問。
stax通過stream的方式來解決sax,dom各自的缺點,同時具有他們大部分的優(yōu)點(我想底層實現(xiàn)是不是通過直接操作文件流的方式,還沒有看它的實現(xiàn)的src,不敢亂說)。stax主要有兩中粒度不同的操作方式 ,一種基于event, 另一種更底層的實現(xiàn)基于cursor。初一看實現(xiàn)方式有點象sax,因為都是基于event的。但是sax把訪問控制權(quán)交給parser(通過callback))了,我們很難控制iterat過程。stax允許我們自己控制iterat.
所以stax的優(yōu)點如下:基于stream的方式,不象dom耗費內(nèi)存資源。又可以自己控制對xml的iterat,不象sax把控制權(quán)交給parser).還有一個優(yōu)點就是可以在iterat的過程中隨時cancel。雖然sax 也可以通過 throw saxexception的方式中斷iterat過程,但畢竟不是一中優(yōu)美的解決方案。當(dāng)然stax的還提供了以stream的方式進行write xml的操作。
具體的stax應(yīng)用可以看ibm的系列教程文章,比較老了了點。http://www-128.ibm.com/developerworks/xml/library/x-tipstx/
具體實現(xiàn),除了bea的一個ri實現(xiàn)外,不知道還有其他的實現(xiàn)沒有(stax jsr好象最早由bea提出來)?
個人感覺stax的應(yīng)用還是有些麻煩,期待(或則是不是已經(jīng)有了?)能有更高層次的封裝(類似于jdom,jaxp實現(xiàn)之類的)。
例三:
使用SAX解析XML
一、 前言
用Java解析XML文檔,最常用的有兩種方法:使用基于事件的XML簡單API(Simple API for XML)稱為SAX和基于樹和節(jié)點的文檔對象模型(Document Object Module)稱為DOM。Sun公司提供了Java API for XML Parsing(JAXP)接口來使用SAX和DOM,通過JAXP,我們可以使用任何與JAXP兼容的XML解析器。
JAXP接口包含了三個包:
(1) org.w
(2) org.xml.sax 用于對XML進行語法分析的事件驅(qū)動的XML簡單API(SAX)
(3) javax.xml.parsers解析器工廠工具,程序員獲得并配置特殊的特殊語法分析器。
二、 前提
DOM編程不要其它的依賴包,因為JDK里自帶的JDK里含有的上面提到的org.w
三、 使用SAX解析XML文檔
SAX是基于事件的簡單API,同樣的我們也是用一個最簡單的例子來看看SAX是如何解析XML的
先來看看我們要解析的XML代碼吧
<?xml version="1.0" encoding="gb2312"?>
<books>
<book email="zhoujunhui">
<name addr="address">rjzjh</name>
<price>jjjjjj</price>
</book>
</books>
簡單的不能再簡單了。但是該有的都有了,根元素、屬性、子節(jié)點。好了,能反應(yīng)問題就行了,下面來看看解析這個XML文件的Java代碼吧!
1 public class SaxParse {
2 public SaxParse(){
3 SAXParserFactory saxfac=SAXParserFactory.newInstance();
4 try {
5 SAXParser saxparser=saxfac.newSAXParser();
6 InputStream is=new FileInputStream("bin/library.xml");
7 saxparser.parse(is,new MySAXHandler());
8 } catch (ParserConfigurationException e) {
9 e.printStackTrace();
10 } catch (SAXException e) {
11 e.printStackTrace();
12 } catch (FileNotFoundException e) {
13 e.printStackTrace();
14 } catch (IOException e) {
15 e.printStackTrace();
16 }
17 }
18 public static void main(String[] args) {
19 new SaxParse();
20 }
21 }
這段代碼比較短,因為SAX是事件驅(qū)動的,它的大部分實現(xiàn)在在另一個Java文件中,先別管另一個文件,我們來一個個地分析吧!
(1)得到SAX解析器的工廠實例
3 SAXParserFactory saxfac=SAXParserFactory.newInstance();
這是一個javax.xml.parsers.SAXParserFactory類的實例
(2)從SAX工廠實例中獲得SAX解析器
5 SAXParser saxparser=saxfac.newSAXParser();
使用javax.xml.parsers.SAXParserFactory工廠的newSAXParser()方法
(3)把要解析的XML文檔轉(zhuǎn)化為輸入流,以便DOM解析器解析它
6 InputStream is=new FileInputStream("bin/library.xml");
InputStream是一個接口。
(4)解析XML文檔
7 saxparser.parse(is,new MySAXHandler());
后面就不用看了,都是些沒用的代碼(相對而言),夠簡單的吧!
注意了,我們新建了一個實例new MySAXHandler()這個實例里面又有什么東西呢?
這個實例就是SAX的精華所在。我們使用SAX解析器時,必須實現(xiàn)內(nèi)容處理器ContentHandler接口中的一些回調(diào)方法,然而我們不須要全部地實現(xiàn)這些方法,還好,我們有org.xml.sax.helpers.DefaultHandler類,看它的類申明:
public class DefaultHandler
implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler
實現(xiàn)了這么多接口啊,其它的先不管了,至少它實現(xiàn)了ContentHandler這一接口。
好了,看看這個類有些什么吧?下面是它的Java代碼!
public class MySAXHandler extends DefaultHandler {
boolean hasAttribute=false;
Attributes attributes=null;
/* (非 Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#startDocument()
*/
public void startDocument() throws SAXException {
System.out.println("文檔開始打印了");
}
/* (非 Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#endDocument()
*/
public void endDocument() throws SAXException {
System.out.println("文檔打印結(jié)束了");
}
/* (非 Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
*/
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if(qName.equals("books")){
return;
}
if(qName.equals("book")){
System.out.println(attributes.getQName(0)+attributes.getValue(0));
}
if(attributes.getLength()>0){
this.attributes=attributes;
this.hasAttribute=true;
}
}
/* (非 Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
*/
public void endElement(String uri, String localName, String qName)
throws SAXException {
if(hasAttribute&&(attributes!=null)){
for(int i=0;i<attributes.getLength();i++){
System.out.println(attributes.getQName(0)+attributes.getValue(0));
}
}
}
/* (非 Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
*/
public void characters(char[] ch, int start, int length)
throws SAXException {
System.out.println(new String(ch,start,length));
}
}
不要看它一大堆,我一一分解給大家看。我們說SAX是基于事件的API,我們這個類實到了ContentHandler接口中的如下方法:
(1)startDocument() 用于處理文檔解析開始事件
public void startDocument() throws SAXException {
System.out.println("文檔開始打印了");
}
(2)endDocument() 用于處理文檔解析結(jié)束事件
public void endDocument() throws SAXException {
System.out.println("文檔打印結(jié)束了");
}
(3)startElement 用于處理元素開始事件
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if(qName.equals("books")){
return;
}
if(qName.equals("book")){
System.out.println(attributes.getQName(0)+attributes.getValue(0));
}
if(attributes.getLength()>0){
this.attributes=attributes;
this.hasAttribute=true;
}
}
第二個參數(shù)String qName表示這個元素的名字,如:
根節(jié)點 <books></books> 它的