欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
解析xml之--SAX
解析xml之--SAX

SAX同DOM一樣也是一個(gè)訪(fǎng)問(wèn)XML文檔的接口。SAX是Simple API for XML的縮寫(xiě)。它不像DOM那樣是W3C的推薦標準。它是由XML-DEV郵件列表的成員開(kāi)發(fā)維護,由David Megginson領(lǐng)導(david@megginson.com)的一個(gè)Public Domain軟件。SAX是一個(gè)徹底的自由軟件,它的作者放棄了對它的所有權利,并且它也被許可用于任何目的(在文章最后附錄了它的版權聲明)。

到現在為止SAX的版本已經(jīng)發(fā)展到2.0。在這個(gè)最新版本中增加了對名稱(chēng)空間(Namespaces)的支持,而且可以通過(guò)對features以及properties的設置來(lái)對解析器做全面的配置,這其中包括設置解析器是否對文檔進(jìn)行有效性驗證,以及怎樣來(lái)處理帶有名稱(chēng)空間的元素名稱(chēng)等。SAX1中的接口已經(jīng)不再使用了,這里只會(huì )討論有關(guān)SAX2的開(kāi)發(fā)。在本文中提到SAX只是指SAX 2。另外,本文的所有例子都是用java編寫(xiě),SAX解析器也使用的是JAVA版本。 

實(shí)現了SAX的解析器有很多,比如Apache的Xerces,Oracle的XML Parser等等。在本文中的例子程序使用的都是Xerces解析器,你可以從 http://xml.apache.org 得到它。讓我們下載得到xerces.jar文件然后將其加入到classpath中去,這樣我們就已經(jīng)建立好環(huán)境(在xerces.jar中已經(jīng)包含了SAX接口,所以不必特意再去尋找SAX類(lèi)庫)。

在SAX API中有兩個(gè)包,org.xml.sax和org.xml.sax.helper。其中org.xml.sax中主要定義了SAX的一些基礎接口,如XMLReader、ContentHandler、ErrorHandler、DTDHandler、EntityResolver等。而在org.xml.sax.helper中則是一些方便開(kāi)發(fā)人員使用的幫助類(lèi),如缺省實(shí)現所有處理器接口的幫助類(lèi)DefaultHandler、方便開(kāi)發(fā)人員創(chuàng )建XMLReader的XMLReaderFactory類(lèi)等等。在這兩個(gè)包中還有一些應用于SAX1的接口,同時(shí)還有幾個(gè)類(lèi)它們只是為了便于將在SAX1上開(kāi)發(fā)的應用移植到SAX2上,在這篇文章中就不涉及了。下面是我們要關(guān)注的接口和類(lèi):

Package org.xml.sax

介紹

Interfaces 接口
Attributes 定義了一個(gè)屬性列表接口,供訪(fǎng)問(wèn)元素的屬性列表而用。
ContentHandler 處理解析文檔內容時(shí)產(chǎn)生的事件。
DTDHandler 處理解析DTD時(shí)的相應事件。
EntityResolver 處理外部實(shí)體。
ErrorHandler 處理解析過(guò)程中所遇到的文檔錯誤事件。
Locator 為了定位解析中產(chǎn)生的內容事件在文檔中的位置而準備的一個(gè)定位器接口。
XMLFilter 提供了一個(gè)方便應用開(kāi)發(fā)的過(guò)濾器接口。
XMLReader 任何兼容SAX2的解析器都要實(shí)現這個(gè)接口,這個(gè)接口讓?xiě)贸绦蚩梢栽O置或查找features和properties,注冊各種事件處理器,以及開(kāi)始解析文檔。
Classes
InputSource 為XML實(shí)體準備的輸入源。
Exceptions
SAXException 包裝了一般的SAX錯誤和警告。
SAXNotRecognizedException 為識別不出某些標識而拋出的異常。
SAXNotSupportedException 為不支持某個(gè)操作而拋出的異常。
SAXParseException 包裝了一個(gè)關(guān)于XML解析的錯誤或者警告。

Package org.xml.sax.helpers

幫助類(lèi)所在的包

Classes 類(lèi)
AttributesImpl 對Attributes接口的缺省實(shí)現
NamespaceSupport 提供名稱(chēng)空間支持。
DefaultHandler 缺省實(shí)現了四個(gè)處理器接口,方便用戶(hù)開(kāi)發(fā),在開(kāi)發(fā)過(guò)程中會(huì )經(jīng)常用到。
LocatorImpl 提供了一個(gè)對Locator接口的實(shí)現
XMLFilterImpl 對過(guò)濾器接口的實(shí)現,使用過(guò)濾器進(jìn)行應用程序開(kāi)發(fā)時(shí),繼承這個(gè)類(lèi)很方便。
XMLReaderFactory 為方便創(chuàng )建不同的XMLReader而提供。也會(huì )經(jīng)常用到。

SAX的設計實(shí)現與DOM是完全不同的!DOM處理XML文檔是基于將XML文檔解析成樹(shù)狀模型,放入內存進(jìn)行處理。而SAX則是采用基于事件驅動(dòng)的處理模式,它將XML文檔轉化成一系列的事件,由單獨的事件處理器來(lái)決定如何處理。為了了解如何使用SAX API處理XML文檔,這里先介紹一下SAX所使用的基于事件驅動(dòng)的處理模式。

這種基于事件的處理模式是一種通用的程序設計模式,被廣泛應用于GUI設計。在JAVA的AWT,SWING以及JAVA BEANS中就有它的身影。而SAX的基于事件驅動(dòng)的處理模式就與上面三者中的非常相像。

基于事件的處理模式主要是圍繞著(zhù)事件源以及事件處理器(或者叫監聽(tīng)器)來(lái)工作的。一個(gè)可以產(chǎn)生事件的對象被稱(chēng)為事件源,而可以針對事件產(chǎn)生響應的對象就被叫做事件處理器。事件源和事件處理器是通過(guò)在事件源中的事件處理器注冊方法連接的。這樣當事件源產(chǎn)生事件后,調用事件處理器相應的處理方法,一個(gè)事件就獲得了處理。當然在事件源調用事件處理器中特定方法的時(shí)候,會(huì )傳遞給事件處理器相應事件的狀態(tài)信息,這樣事件處理器才能夠根據事件信息來(lái)決定自己的行為。

在SAX接口中,事件源是org.xml.sax包中的XMLReader,它通過(guò)parse()方法來(lái)開(kāi)始解析XML文檔并根據文檔內容產(chǎn)生事件。而事件處理器則是org.xml.sax包中的ContentHandler,DTDHandler,ErrorHandler,以及EntityResolver這四個(gè)接口。它們分別處理事件源在解析過(guò)程中產(chǎn)生的不同種類(lèi)的事件(其中DTDHandler是為解析文檔DTD時(shí)而用)。而事件源XMLReader和這四個(gè)事件處理器的連接是通過(guò)在XMLReader中的相應的事件處理器注冊方法set***()來(lái)完成的。詳細介紹請見(jiàn)下表:

處理器名稱(chēng) 所處理事件 注冊方法
org.xml.sax.ContentHandler 跟文檔內容有關(guān)的所有事件:
  1. 文檔的開(kāi)始和結束
  2. XML元素的開(kāi)始和結束
  3. 可忽略的實(shí)體
  4. 名稱(chēng)空間前綴映射開(kāi)始和結束
  5. 處理指令
  6. 字符數據和可忽略的空格
XMLReader中的setContentHandler(ContentHandler handler)方法
org.xml.sax.ErrorHandler 處理XML文檔解析時(shí)產(chǎn)生的錯誤。如果一個(gè)應用程序沒(méi)有注冊一個(gè)錯誤處理器類(lèi),會(huì )發(fā)生不可預料的解析器行為。 setErrorHandler(ErrorHandler handler)
org.xml.sax.DTDHandler 處理對文檔DTD進(jìn)行解析時(shí)產(chǎn)生的相應事件 setDTDHandler(DTDHandler handler)
org.xml.sax.EntityResolver 處理外部實(shí)體 setEntityResolver(EntityResolver resolver)

在這四個(gè)處理器接口中,對我們最重要的是ContentHandler接口。下面讓我們看一下對其中方法的說(shuō)明:

方法名稱(chēng) 方法說(shuō)明
public void setDocumentLocator(Locator locator) 設置一個(gè)可以定位文檔內容事件發(fā)生位置的定位器對象
public void startDocument() throws SAXException 用于處理文檔解析開(kāi)始事件
public void endDocument() throws SAXException 用于處理文檔解析結束事件
public void startPrefixMapping(java.lang.String prefix, java.lang.String uri) throws SAXException 用于處理前綴映射開(kāi)始事件,從參數中可以得到前綴名稱(chēng)以及所指向的uri
public void endPrefixMapping(java.lang.String prefix) throws SAXException 用于處理前綴映射結束事件,從參數中可以得到前綴名稱(chēng)
public void startElement(java.lang.String namespaceURI,java.lang.String localName,java.lang.String qName,Attributes atts) throws SAXException 處理元素開(kāi)始事件,從參數中可以獲得元素所在名稱(chēng)空間的uri,元素名稱(chēng),屬性列表等信息
public void endElement(java.lang.String namespaceURI, java.lang.String localName, java.lang.String qName) throws SAXException 處理元素結束事件,從參數中可以獲得元素所在名稱(chēng)空間的uri,元素名稱(chēng)等信息
public void characters(char[] ch, int start, int length) throws SAXException 處理元素的字符內容,從參數中可以獲得內容
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException 處理元素的可忽略空格
public void processingInstruction(java.lang.String target, java.lang.String data) throws SAXException 處理解析中產(chǎn)生的處理指令事件

這里再介紹一下org.xml.sax.XMLReader中的方法,然后讓我們看一個(gè)具體的例子。XMLReader是所有兼容SAX2的解析器都要實(shí)現的接口,由它的方法開(kāi)始解析文檔,并且調用它的注冊方法來(lái)注冊各種事件處理器。請看下表:

方法名稱(chēng) 方法介紹
public Boolean getFeature(java.lang.String name)throws SAXNotRecognizedException,SAXNotSupportedException 得到某個(gè)feature的值
public void setFeature(java.lang.String name,boolean value) throws SAXNotRecognizedException,SAXNotSupportedException 設置某個(gè)feature的值,例如,如果需要解析器支持對文檔進(jìn)行驗證那么就這么調用本方法。myReader.setFeature(http://xml.org/sax/features/validation,true);其中myReader是XMLReader的實(shí)例。
public java.lang.Object getProperty(java.lang.String name)throws SAXNotRecognizedException,SAXNotSupportedException 返回一個(gè)property的值
public void setProperty(java.lang.String name,java.lang.Object value)throws SAXNotRecognizedException,SAXNotSupportedException 設置一個(gè)property的值
public void setEntityResolver(EntityResolver resolver) 注冊處理外部實(shí)體的EntityResolver
public EntityResolver getEntityResolver() 得到系統中注冊的EntityResolver
public void setDTDHandler(DTDHandler handler) 注冊處理DTD解析事件的DTDHandler
public DTDHandler getDTDHandler() 得到系統中注冊的DTDHandler
public void setContentHandler(ContentHandler handler) 注冊處理XML文檔內容解析事件的ContentHandler
public ContentHandler getContentHandler() 得到系統中注冊的ContentHandler
public void setErrorHandler(ErrorHandler handler) 注冊處理文檔解析錯誤事件的ErrorHandler
public ErrorHandler getErrorHandler() 得到系統中注冊的ErrorHandler
public void parse(InputSource input)throws java.io.IOException,SAXException 開(kāi)始解析一個(gè)XML文檔。
public void parse(java.lang.String systemId)throws java.io.IOException,SAXException 開(kāi)始解析一個(gè)使用系統標識符標識的XML文檔。這個(gè)方法只是上面方法的一個(gè)快捷方式它等同于:parse(new InputSource(systemId));

讓我們通過(guò)例子來(lái)看一下使用SAX解析XML文檔的應用程序是如何建立的。下面是在應用程序中被處理的XML文檔。為了說(shuō)明SAX對名稱(chēng)空間的支持,我在這里特意加了一個(gè)有名稱(chēng)空間的元素,在這里會(huì )產(chǎn)生相應的前綴映射開(kāi)始和結束事件。

<?xml version="1.0" encoding="GB2312"?><我的書(shū)架 >    <技術(shù)書(shū)籍>        <圖書(shū)>            <書(shū)名>JAVA 2編程詳解</書(shū)名>            <價(jià)格 貨幣單位="人民幣">150</價(jià)格>            <購買(mǎi)日期>2000,1,24</購買(mǎi)日期>        </圖書(shū)>          </技術(shù)書(shū)籍>    <book:文學(xué)書(shū)籍 xmlns:book="http://javausr.com"/>    <歷史書(shū)籍/></我的書(shū)架>

這里的例子程序只是簡(jiǎn)單地將遇到的事件信息打印出來(lái)。我們首先實(shí)現ContentHandler接口來(lái)處理在XML文檔解析過(guò)程中產(chǎn)生的和文檔內容相關(guān)的事件,代碼如下所示MyContentHandler.java:
package com.javausr.saxexample;

import org.xml.sax.Attributes;import org.xml.sax.ContentHandler;import org.xml.sax.Locator;import org.xml.sax.SAXException;public class MyContentHandler implements ContentHandler {    private StringBuffer buf;    public void setDocumentLocator( Locator locator ) {    }    public void startDocument() throws SAXException {        buf=new StringBuffer();        System.out.println("*******開(kāi)始解析文檔*******");    }    public void endDocument() throws SAXException {        System.out.println("*******解析文檔結束*******");    }    public void processingInstruction( String target, String instruction )        throws SAXException {    }    public void startPrefixMapping( String prefix, String uri ) {          System.out.println("\n前綴映射: " + prefix +" 開(kāi)始!"+ "  它的URI是:" + uri);    }    public void endPrefixMapping( String prefix ) {          System.out.println("\n前綴映射: "+prefix+" 結束!");    }    public void startElement( String namespaceURI, String localName,                                  String fullName, Attributes attributes )                          throws SAXException {        System.out.println("\n 元素: " + "["+fullName+"]" +" 開(kāi)始解析!");        // 打印出屬性信息        for ( int i = 0; i < attributes.getLength(); i++ ) {            System.out.println("\t屬性名稱(chēng):" + attributes.getLocalName(i)                + " 屬性值:" + attributes.getValue(i));        }    }    public void endElement( String namespaceURI, String localName,                                                      String fullName )                          throws SAXException {        //打印出非空的元素內容并將StringBuffer清空                        String nullStr="";        if (!buf.toString().trim().equals(nullStr)){           System.out.println("\t內容是: " + buf.toString().trim());        }        buf.setLength(0);        //打印元素解析結束信息        System.out.println("元素: "+"["+fullName+"]"+" 解析結束!");                  }    public void characters( char[] chars, int start, int length )                                throws SAXException {          //將元素內容累加到StringBuffer中                          buf.append(chars,start,length);    }    public void ignorableWhitespace( char[] chars, int start, int length )                                  throws SAXException {    }    public void skippedEntity( String name ) throws SAXException {    }}

下面讓我們創(chuàng )建一個(gè)調入了xerces解析器來(lái)實(shí)現XMLReader接口、并使用剛才創(chuàng )建的MyContentHandler來(lái)處理相應解析事件的MySAXApp.java類(lèi):
package com.javausr.saxexample;

import org.xml.sax.XMLReader;import org.xml.sax.helpers.XMLReaderFactory;import org.xml.sax.ContentHandler;import org.xml.sax.SAXException;import java.io.IOException;public class MySAXApp {  public static void main( String[] args ) {        if ( args.length != 1 ) {      System.out.println("輸入: java MySAXApp ");      System.exit(0);    }    try {        // 初始化reader        XMLReader reader = XMLReaderFactory.createXMLReader                          ("org.apache.xerces.parsers.SAXParser") ;        // 創(chuàng  )建ContentHandler的實(shí)例        ContentHandler contentHandler = new MyContentHandler();        // 在reader中注冊實(shí)例化的ContentHandler        reader.setContentHandler( contentHandler );        // 開(kāi)始解析文檔        reader.parse(args[0]);    } catch ( IOException e ) {        System.out.println("讀入文檔時(shí)錯: " + e.getMessage());    } catch ( SAXException e ) {        System.out.println("解析文檔時(shí)錯: " + e.getMessage());    }  }}

下面讓我們來(lái)看一下執行結果:

D:\sax\classes>java com.javausr.saxexample.MySAXApp d:\book.xml*******開(kāi)始解析文檔*******元素: [我的書(shū)架] 開(kāi)始解析!元素: [技術(shù)書(shū)籍] 開(kāi)始解析!元素: [圖書(shū)] 開(kāi)始解析!元素: [書(shū)名] 開(kāi)始解析!        內容是: JAVA 2編程詳解元素: [書(shū)名] 解析結束!元素: [價(jià)格] 開(kāi)始解析!        屬性名稱(chēng):貨幣單位 屬性值:人民幣        內容是: 150元素: [價(jià)格] 解析結束!元素: [購買(mǎi)日期] 開(kāi)始解析!        內容是: 2000,1,24元素: [購買(mǎi)日期] 解析結束!元素: [圖書(shū)] 解析結束!元素: [技術(shù)書(shū)籍] 解析結束!前綴映射: book 開(kāi)始!  它的URI是:http://javausr.com元素: [book:文學(xué)書(shū)籍] 開(kāi)始解析!元素: [book:文學(xué)書(shū)籍] 解析結束!前綴映射: book 結束!元素: [歷史書(shū)籍] 開(kāi)始解析!元素: [歷史書(shū)籍] 解析結束!元素: [我的書(shū)架] 解析結束!*******解析文檔結束*******

上面就是使用SAX解析一個(gè)XML文檔的基本過(guò)程,但是MyContentHandler只是處理了解析過(guò)程中和文檔內容相關(guān)的事件,如果在解析過(guò)程中出現了錯誤那我們需要實(shí)現ErrorHandler接口來(lái)處理。如果不注冊一個(gè)錯誤處理器來(lái)處理的話(huà),那么錯誤事件將不會(huì )被報告,而且解析器會(huì )出現不可預知的行為。在解析過(guò)程中產(chǎn)生的錯誤被分成了3類(lèi),它們分別是warning,error,以及fatalerror,也就是說(shuō)在ErrorHandler中有這么三個(gè)相應的方法來(lái)處理這些錯誤事件。下面是對這三個(gè)錯誤處理方法的介紹:

方法名稱(chēng) 方法介紹
warning() SAX解析器將用這個(gè)方法來(lái)報告在XML1.0規范中定義的非錯誤(error)或者致命錯誤(fatal error)的錯誤狀態(tài)。對這個(gè)錯誤缺省的行為是什么也不做。SAX解析器必須在調用這個(gè)方法后繼續提供正常的解析事件:應用程序應該能繼續處理完文檔。
error() 這個(gè)方法對應在W3C XML 1.0規范的1.2部分中定義的"error"概念。例如,一個(gè)帶有有效性驗證的解析器會(huì )使用這個(gè)方法來(lái)報告違反有效性驗證的情況。一個(gè)帶有有效性驗證的解析器會(huì )使用這個(gè)方法來(lái)報告違背有些性約束的情況。缺省的行為是什么也不做。SAX解析器必須在調用這個(gè)方法后繼續提供正常的解析事件:應用程序應該能繼續處理完文檔。如果應用程序做不到這樣,則解析器即使在XML1.0規范沒(méi)有要求的情況下也要報告一個(gè)致命錯誤。
fatalError() 這個(gè)方法對應在W3C XML1.0規范的1.2部分定義的"fatal error"概念。例如,一個(gè)解析器會(huì )使用這個(gè)方法來(lái)報告違反格式良好約束的情況。在解析器調用這個(gè)方法后應用程序必須表明這個(gè)文檔是不可使用的,而且應該只是為了收集錯誤信息而繼續進(jìn)行處理(如果需要的話(huà)):實(shí)際上,一旦在這個(gè)方法被調用后SAX解析器可以停止報告任何事件。

下面是實(shí)現了ErrorHandler接口的MyErrorHandler.java類(lèi):
package com.javausr.saxexample;

import org.xml.sax.ErrorHandler;import org.xml.sax.SAXParseException;import org.xml.sax.SAXException;public class MyErrorHandler implements ErrorHandler {    public void warning( SAXParseException exception ) {        System.out.println("*******WARNING******");        System.out.println("\t行:\t" + exception.getLineNumber());        System.out.println("\t列:\t" + exception.getColumnNumber());        System.out.println("\t錯誤信息:\t" + exception.getMessage());        System.out.println("********************");    }    public void error( SAXParseException exception ) throws SAXException{        System.out.println("******* ERROR ******");        System.out.println("\t行:\t" + exception.getLineNumber());        System.out.println("\t列:\t" + exception.getColumnNumber());        System.out.println("\t錯誤信息:\t" + exception.getMessage());        System.out.println("********************");    }    public void fatalError( SAXParseException exception ) throws SAXException {        System.out.println("******** FATAL ERROR ********");        System.out.println("\t行:\t" + exception.getLineNumber());        System.out.println("\t列:\t" + exception.getColumnNumber());        System.out.println("\t錯誤信息:\t" + exception.getMessage());        System.out.println("*****************************");    }}

我們也要對MySAXApp.java類(lèi)做一些修改(在源代碼中藍色標出的部分)使它使用MyErrorHandler.java:
package com.javausr.saxexample;

import org.xml.sax.XMLReader;import org.xml.sax.helpers.XMLReaderFactory;import org.xml.sax.ContentHandler;//引入ErrorHandlerimport org.xml.sax.ErrorHandler;import org.xml.sax.SAXException;import java.io.IOException;public class MySAXApp {            public static void main( String[] args ) {                  if ( args.length != 1 ) {            System.out.println("輸入: java MySAXApp ");            System.exit(0);        }        try {            // 初始化reader            XMLReader reader = XMLReaderFactory.createXMLReader                               ("org.apache.xerces.parsers.SAXParser") ;            // 創(chuàng  )建ContentHandler的實(shí)例            ContentHandler contentHandler = new MyContentHandler();            // 在reader中注冊實(shí)例化的ContentHandler            reader.setContentHandler( contentHandler );            // 創(chuàng  )建ErrorHandler的實(shí)例            ErrorHandler errorHandler = new MyErrorHandler();            // 在reader中注冊實(shí)例化的ErrorHandler            reader.setErrorHandler( errorHandler );            // 開(kāi)始解析文檔            reader.parse(args[0]);    } catch ( IOException e ) {        System.out.println("讀入文檔時(shí)錯: " + e.getMessage());    } catch ( SAXException e ) {        System.out.println("解析文檔時(shí)錯: " + e.getMessage());    }  }

讓我們人為制造些錯誤來(lái)檢查一下我們的錯誤處理器工作情況。刪除元素<購買(mǎi)日期>的閉合標記,這樣會(huì )產(chǎn)生一個(gè)fatal error,下面是執行結果:
D:\sax\classes>java com.javausr.saxexample.MySAXApp d:\book.xml

*******開(kāi)始解析文檔*******元素: [我的書(shū)架] 開(kāi)始解析!元素: [技術(shù)書(shū)籍] 開(kāi)始解析!元素: [圖書(shū)] 開(kāi)始解析!元素: [書(shū)名] 開(kāi)始解析!元素: [書(shū)名] 開(kāi)始解析!        內容是: JAVA 2編程詳解元素: [書(shū)名] 解析結束!元素: [價(jià)格] 開(kāi)始解析!        屬性名稱(chēng):貨幣單位 屬性值:人民幣        內容是: 150元素: [價(jià)格] 解析結束!元素: [購買(mǎi)日期] 開(kāi)始解析!******** FATAL ERROR ********        行:     8        列:     7        錯誤信息:       The element type "購買(mǎi)日期" must be terminated by the matching end-tag "</購買(mǎi)日期>".*****************************解析文檔時(shí)錯: Stopping after fatal error: The element type "購買(mǎi)日期" must be terminated by the matching end-tag "</購買(mǎi)日期>".

現在總結一下如何書(shū)寫(xiě)基于SAX的應用程序。一般步驟如下:

  1. 實(shí)現一個(gè)或多個(gè)處理器接口(ContentHandler, ErrorHandler, DTDHandler ,or EntityResover)。
  2. 創(chuàng )建一個(gè)XMLReader類(lèi)的實(shí)例。
  3. 在新的XMLReader實(shí)例中通過(guò)大量的set*****() 方法注冊一個(gè)事件處理器的實(shí)例
  4. 調用XMLReader的parse()方法來(lái)處理文檔。

 
現在的程序是比較完整了,但還有許多可以改進(jìn)的地方。首先在我們實(shí)現的MyContentHandler.java中,你會(huì )發(fā)現有很多方法實(shí)際上什么也沒(méi)有做,但為了實(shí)現ContentHandler接口,不得不把它們寫(xiě)出來(lái),這樣很是麻煩。SAX API已經(jīng)考慮到這個(gè)問(wèn)題,在它的org.xml.sax.helper包中為我們提供了一個(gè)方便實(shí)現各種處理器接口的幫助類(lèi)DefaultHandler。這個(gè)類(lèi)缺省實(shí)現了上面提到的4個(gè)處理器接口。這樣我們只需繼承這個(gè)類(lèi),然后覆蓋我們想要實(shí)現的事件處理方法即可。下面我們來(lái)新建一個(gè)繼承了DefaultHandler的MyDefaultHandler.java類(lèi),然后把在MyContentHandler.java和MyErrorHandler.java中實(shí)現的事件處理方法照搬到MyDefaultHandler.java類(lèi)中,那些沒(méi)有使用的方法就不必重復了。這里是MyDefaultHandler.java:
package com.javausr.saxexample;

import org.xml.sax.*;import org.xml.sax.helpers.*;import java.io.*;public class MyDefaultHandler extends DefaultHandler {    private StringBuffer buf;    public void startDocument() throws SAXException {        buf=new StringBuffer();        System.out.println("*******開(kāi)始解析文檔*******");    }    public void endDocument() throws SAXException {        System.out.println("*******解析文檔結束*******");    }    public void startPrefixMapping( String prefix, String uri ) {System.out.println("\n前綴映射: " + prefix +" 開(kāi)始!"+ "  它的URI是:"+uri);    }    public void endPrefixMapping( String prefix ) {       System.out.println("\n前綴映射: "+prefix+" 結束!");    }    public void startElement( String namespaceURI, String localName,                                  String fullName, Attributes attributes )                          throws SAXException {        System.out.println("\n元素: " + "["+fullName+"]" +" 開(kāi)始解析!");        // 打印出屬性信息        for ( int i = 0; i < attributes.getLength(); i++ ) {            System.out.println("\t屬性名稱(chēng):" + attributes.getLocalName(i)                + " 屬性值:" + attributes.getValue(i));        }    }    public void endElement( String namespaceURI, String localName,                                                      String fullName )                          throws SAXException {       //打印出非空的元素內容并將StringBuffer清空       String nullStr="";       if (!buf.toString().trim().equals(nullStr)){          System.out.println("\t內容是: " + buf.toString().trim());       }       buf.setLength(0);       //打印元素解析結束信息        System.out.println("元素: "+"["+fullName+"]"+" 解析結束!");    }    public void characters( char[] chars, int start, int length )                                throws SAXException {       //將元素內容累加到StringBuffer中       buf.append(chars,start,length);    }    public void warning( SAXParseException exception ) {        System.out.println("*******WARNING******");        System.out.println("\t行:\t" + exception.getLineNumber());        System.out.println("\t列:\t" + exception.getColumnNumber());        System.out.println("\t錯誤信息:\t" + exception.getMessage());        System.out.println("********************");    }    public void error( SAXParseException exception ) throws SAXException{        System.out.println("******* ERROR ******");        System.out.println("\t行:\t" + exception.getLineNumber());        System.out.println("\t列:\t" + exception.getColumnNumber());        System.out.println("\t錯誤信息:\t" + exception.getMessage());        System.out.println("********************");    }    public void fatalError( SAXParseException exception ) throws SAXException {        System.out.println("******** FATAL ERROR ********");        System.out.println("\t行:\t" + exception.getLineNumber());        System.out.println("\t列:\t" + exception.getColumnNumber());        System.out.println("\t錯誤信息:\t" + exception.getMessage());        System.out.println("*****************************");    }}

我們也要對MySAXApp.java做相應的修改,修改已在源代碼中標出:
package com.javausr.saxexample;

import org.xml.sax.XMLReader;import org.xml.sax.helpers.XMLReaderFactory;//引入DefaultHandlerimport org.xml.sax.helpers.DefaultHandler;import org.xml.sax.SAXException;import java.io.IOException;public class MySAXApp {  public static void main( String[] args ) {              if ( args.length != 1 ) {        System.out.println("輸入: java MySAXApp ");        System.exit(0);      }    try {        // 初始化reader        XMLReader reader = XMLReaderFactory.createXMLReader                         ("org.apache.xerces.parsers.SAXParser") ;        // 創(chuàng  )建DefaultHandler的實(shí)例        DefaultHandler defaultHandler=new MyDefaultHandler();        //在reader中將defaultHandler注冊為ContentHandler        reader.setContentHandler(defaultHandler);        //在reader中將defaultHandler注冊為ErrorHandler        reader.setErrorHandler(defaultHandler);        // 開(kāi)始解析文檔        reader.parse(args[0]);    } catch ( IOException e ) {        System.out.println("讀入文檔時(shí)錯: " + e.getMessage());    } catch ( SAXException e ) {        System.out.println("解析文檔時(shí)錯: " + e.getMessage());    }  }}

使用過(guò)濾器
在SAX API中還提供了一個(gè)過(guò)濾器接口org.xml.sax.XMLFilter,以及對它的缺省實(shí)現org.xml.sax.helper.XMLFilterImpl。使用它們可以很容易的開(kāi)發(fā)出復雜的SAX應用。這里要先介紹一下過(guò)濾器設計模式。這個(gè)設計模式很好理解,就像一個(gè)凈化水的過(guò)程。自然界中的水流過(guò)一個(gè)個(gè)的過(guò)濾器得到最后的飲用水。這些過(guò)濾器,有的是清除水中的泥沙,有的是殺滅水中的細菌,總之不同的過(guò)濾器完成不同的任務(wù)。在應用開(kāi)發(fā)中,我們讓被改造的對象(這里是事件流)通過(guò)這些過(guò)濾器對象從而得到改造后符合要求的對象。這樣,在過(guò)濾器的幫助之下,我們可以非常方便的在每個(gè)過(guò)濾器中實(shí)現一個(gè)特定功能,從而創(chuàng )建結構復雜的應用程序。在應用程序中你可以構造任意多個(gè)過(guò)濾器,將它們串接起來(lái)完成任務(wù)。

在SAX API中org.xml.sax.XMLFilter接口繼承了org.xml.sax.XMLReader接口。它與XMLReader不同的是它不像XMLReader那樣通過(guò)解析文檔來(lái)獲取事件,而是從其他XMLReader中獲取事件,當然這也包括從其他的XMLFilter中獲取事件。在org.xml.sax.XMLFilter中有兩個(gè)方法:

方法名稱(chēng) 方法描述
Public void setParent(XMLReader parent) 設置父XMLReader。這個(gè)方法讓?xiě)贸绦驅⑦@個(gè)過(guò)濾器連接到它的父XMLReader (也可能是另一個(gè)過(guò)濾器)。
Public XMLReader getParent() 獲取父XMLReader。這個(gè)方法讓?xiě)贸绦蚩梢圆樵?xún)父XMLReader(也可能是另一個(gè)過(guò)濾器)。最好不要在父XMLReader中直接進(jìn)行任何操作:讓所有的事件通過(guò)這個(gè)過(guò)濾器來(lái)處理。

我們不需要自己實(shí)現org.xml.sax.XMLFilter接口,在SAX API 中提供了一個(gè)org.xml.sax.helper.XMLFilterImpl類(lèi),它不僅實(shí)現了org.xml.sax.XMLFilter接口而且還實(shí)現了其他四個(gè)核心處理器接口,我們只需要繼承它即可完成我們的過(guò)濾器。剛開(kāi)始使用XMLFilterImpl比較容易讓人迷惑,你只需要記?。?

  1. 在你繼承的XMLFilterImpl類(lèi)中用set****()方法這冊的事件處理器是給過(guò)濾后的事件流而用的。
  2. 在你繼承的XMLFilterImpl類(lèi)中實(shí)現的那些事件處理方法,比如startDocument()、startElement()、characters()等才是這個(gè)過(guò)濾器實(shí)現它自身功能的地方。而通過(guò)繼承XMLFilterImpl而實(shí)現的這個(gè)類(lèi)會(huì )被造型成各種處理器(它本身實(shí)現了四個(gè)處理器接口)用在它的父XMLReader中。這個(gè)步驟會(huì )在你調用自己創(chuàng )建的過(guò)濾器的parse()方法開(kāi)始解析文檔時(shí)被自動(dòng)執行(請參見(jiàn)SAX源代碼)。
  3. 如果不是使用帶參數的構造器創(chuàng )建XMLFilter對象,務(wù)必使用setParent(XMLReader parent)方法連接它的父XMLReader。
  4. 如果使用多個(gè)過(guò)濾器的話(huà),執行順序是從父親到最后的過(guò)濾器。但是開(kāi)始解析卻要調用最后一個(gè)過(guò)濾器的parse()方法。

 

下面讓我們結合已有的例子來(lái)演示過(guò)濾器org.xml.sax.XMLFilter的作用。我們在這個(gè)過(guò)濾器中要過(guò)濾掉<技術(shù)書(shū)籍>這個(gè)元素,最后得到的事件流還是由上邊實(shí)現的MyDefaultHandler來(lái)處理。源代碼如下MyFilter.java:
package com.javausr.saxexample;

import org.xml.sax.*;import org.xml.sax.helpers.*;import java.io.*;public class MyFilter extends XMLFilterImpl {   private String currentElement;   public MyFilter( XMLReader parent ) {      super(parent);   }   /**    * 過(guò)濾掉元素<技術(shù)書(shū)籍>的開(kāi)始事件    **/   public void startElement( String namespaceURI, String localName,                             String fullName, Attributes attributes )      throws SAXException {         currentElement = localName;         if ( !localName.equals("技術(shù)書(shū)籍") ) {           super.startElement(namespaceURI, localName, fullName, attributes);         }      }   /**    * 過(guò)濾掉元素<技術(shù)書(shū)籍>的結束事件    **/   public void endElement(String namespaceURI, String localName, String                          fullName)      throws SAXException {         if ( !localName.equals("技術(shù)書(shū)籍") ) {            super.endElement(namespaceURI, localName, fullName);         }    }   /**    * 過(guò)濾掉元素<技術(shù)書(shū)籍>中的內容    **/    public void characters(char[] buffer, int start, int length) throws SAXException {        if ( !currentElement.equals("技術(shù)書(shū)籍") ) {          super.characters( buffer,start,length );        }    }}

同樣我們還要修改MySAXApp.java,修改后的代碼如下所示:
package com.javausr.saxexample;

import org.xml.sax.XMLReader;import org.xml.sax.helpers.XMLReaderFactory;import org.xml.sax.helpers.DefaultHandler;//引入XMLFilterimport org.xml.sax.XMLFilter;import org.xml.sax.SAXException;import java.io.IOException;public class MySAXApp {  public static void main( String[] args ) {        if ( args.length != 1 ) {      System.out.println("輸入: java MySAXApp ");      System.exit(0);    }    try {            // 初始化reader        XMLReader reader = XMLReaderFactory.createXMLReader                           ("org.apache.xerces.parsers.SAXParser") ;        //初始化過(guò)濾器        XMLFilter myFilter=new MyFilter(reader);        // 創(chuàng  )建DefaultHandler的實(shí)例        DefaultHandler defaultHandler=new MyDefaultHandler();        //為過(guò)濾后的事件流設置ContentHandler        myFilter.setContentHandler(defaultHandler);        //為過(guò)濾后的事件流設置ErrorHandler        myFilter.setErrorHandler(defaultHandler);            // 開(kāi)始解析文檔,注意是使用myFilter中的解析方法        myFilter.parse(args[0]);      } catch ( IOException e ) {            System.out.println("讀入文檔時(shí)錯: " + e.getMessage());      } catch ( SAXException e ) {            System.out.println("解析文檔時(shí)錯: " + e.getMessage());    }  }}

這里是最后的執行結果,我們可以發(fā)現有關(guān)<技術(shù)書(shū)籍>的全部事件已經(jīng)被過(guò)濾掉了。認真看一下結果,你一定覺(jué)得奇怪,為什么<技術(shù)書(shū)籍>元素的孩子元素仍然存在。請記住SAX是把XML文檔解析成事件流,所有沒(méi)有被過(guò)濾的事件都會(huì )保留下來(lái)。這就是SAX和DOM的最大不同。在DOM中文檔被解析成了樹(shù)狀模型,如果你刪除一個(gè)元素,那么這個(gè)元素以及它的孩子元素就都會(huì )被刪除,這符合樹(shù)狀模型的特點(diǎn)。

D:\sax\classes>java com.javausr.saxexample.MySAXApp d:\book.xml

*******開(kāi)始解析文檔*******元素: [我的書(shū)架] 開(kāi)始解析!元素: [圖書(shū)] 開(kāi)始解析!元素: [書(shū)名] 開(kāi)始解析!        內容是: JAVA 2編程詳解元素: [書(shū)名] 解析結束!元素: [價(jià)格] 開(kāi)始解析!        屬性名稱(chēng):貨幣單位 屬性值:人民幣        內容是: 150元素: [價(jià)格] 解析結束!元素: [購買(mǎi)日期] 開(kāi)始解析!        內容是: 2000,1,24元素: [購買(mǎi)日期] 解析結束!元素: [圖書(shū)] 解析結束!前綴映射: book 開(kāi)始!  它的URI是:http://javausr.com元素: [book:文學(xué)書(shū)籍] 開(kāi)始解析!元素: [book:文學(xué)書(shū)籍] 解析結束!前綴映射: book 結束!元素: [歷史書(shū)籍] 開(kāi)始解析!元素: [歷史書(shū)籍] 解析結束!元素: [我的書(shū)架] 解析結束!*******解析文檔結束*******


首先是有關(guān)元素內容的問(wèn)題,在SAX API定義中元素內容可以在一次事件(由characters()方法處理)中返回,也可以在多次事件中返回,這樣我們就應該考慮不能一次得到所有內容數據的情況。一般的解決辦法是定義一個(gè)StringBuffer由它來(lái)保存內容數據,在元素結束或者新元素開(kāi)始的時(shí)候清空這個(gè)StringBuffer從而可以保存新的內容數據。請參考上面的相應的源代碼。

還有在SAX API中特意提到從 characters(char[] ch,int start,int length)方法中提取數據時(shí)一定不要從返回的字符數組范圍之外讀取,這一點(diǎn)我們也要切記。

另一個(gè)值得注意的問(wèn)題是,在 startElement()方法中返回的Attributes屬性列表中的屬性順序并沒(méi)有被特意規定,在不同的SAX實(shí)現中也各不相同。所以我們在編寫(xiě)程序時(shí)不要把屬性順序想成一定的。


通過(guò)上面的介紹我想大家對SAX已經(jīng)有了一個(gè)基本的了解。每一個(gè)進(jìn)行XML開(kāi)發(fā)的編程人員都知道DOM,那為什么在有了DOM這個(gè)功能強大的文檔對象模型之后,我們還需要SAX?這就要從它們根本不同的實(shí)現方法上來(lái)分析。DOM解析器是通過(guò)將XML文檔解析成樹(shù)狀模型并將其放入內存來(lái)完成解析工作的,而后對文檔的操作都是在這個(gè)樹(shù)狀模型上完成的。這個(gè)在內存中的文檔樹(shù)將是文檔實(shí)際大小的幾倍。這樣做的好處是結構清除、操作方便,而帶來(lái)的麻煩就是極其耗費系統資源。而SAX正好克服了DOM的缺點(diǎn)。SAX解析器的處理過(guò)程是通讀整個(gè)文檔,根據文檔內容產(chǎn)生事件,而把對這些事件的處理交由事件處理器處理。SAX不需要在內存中保存整個(gè)文檔,它對系統資源的節省是顯而易見(jiàn)的。這樣在一些需要處理大型XML文檔和性能要求比較高的場(chǎng)合就要用SAX了。

下面的表格列出了SAX和DOM在一些方面的對照:

SAX DOM
順序讀入文檔并產(chǎn)生相應事件,可以處理任何大小的XML文檔 在內存中創(chuàng )建文檔樹(shù),不適于處理大型XML文檔。
只能對文檔按順序解析一遍,不支持對文檔的隨意訪(fǎng)問(wèn)。 可以隨意訪(fǎng)問(wèn)文檔樹(shù)的任何部分,沒(méi)有次數限制。
只能讀取XML文檔內容,而不能修改 可以隨意修改文檔樹(shù),從而修改XML文檔。
開(kāi)發(fā)上比較復雜,需要自己來(lái)實(shí)現事件處理器。 易于理解,易于開(kāi)發(fā)。
對開(kāi)發(fā)人員而言更靈活,可以用SAX創(chuàng )建自己的XML對象模型。 已經(jīng)在DOM基礎之上創(chuàng )建好了文檔樹(shù)。

通過(guò)對SAX和DOM的分析,它們各有自己的不同應用領(lǐng)域:

SAX適于處理下面的問(wèn)題:

  1. 對大型文檔進(jìn)行處理。
  2. 只需要文檔的部分內容,或者只需要從文檔中得到特定信息。
  3. 想創(chuàng )建自己的對象模型的時(shí)候。

DOM適于處理下面的問(wèn)題:

  1. 需要對文檔進(jìn)行修改
  2. 需要隨機對文檔進(jìn)行訪(fǎng)問(wèn),例如XSLT解析器。


 

三種構造解析器方法:

 方法1:

import java.io.*;
import javax.xml.parsers.*;
import org.xml.sax.*;

        SAXParserFactory spf 
= SAXParserFactory.newInstance();
        SAXParser sp 
= null;
        
try {
            sp 
= spf.newSAXParser();
            File file 
= new File("src/c03/students.xml");
            sp.parse(file, 
new SAXPrinter());
        }
        
catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
        
catch (SAXException e) {
            e.printStackTrace();
        }
        
catch (IOException e) {
            e.printStackTrace();
        }

方法2:

import org.apache.xerces.parsers.SAXParser;
import org.xml.sax.InputStream;
import java.io.FileInputStream;

SAXParser saxParser 
= new SAXParser();
saxParser.setContentHandler(
new EventHandler());
saxParser.parse(
new InputSource(new FileInputStream("game.xml")));

方法3:

import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import java.io.IOException;

       
// 初始化reader
        XMLReader reader = XMLReaderFactory.createXMLReader
                          (
"org.apache.xerces.parsers.SAXParser") ;

        
// 創(chuàng )建ContentHandler的實(shí)例
        ContentHandler contentHandler = new MyContentHandler();

        
// 在reader中注冊實(shí)例化的ContentHandler
        reader.setContentHandler( contentHandler );

        
// 開(kāi)始解析文檔
        reader.parse(args[0]);

 

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
幾個(gè)解析XML的例子
Java & xml學(xué)習筆記 SAX篇
android解析XML總結(SAX、Pull、Dom三種方式)
JAXP(Java API for XML Parsing)
JAVA解析xml的四種方式比較
JR - 精品文章 - Java語(yǔ)言的XML驗證API
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久