posts - 56, comments - 77, trackbacks - 0, articles - 1
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          快速與簡單并非天生不可兼得, 相反, 簡單的東西應該是快速的


          在使用 SAX 解析 XML 的過程中, 碰到了以下問題:
          1. SAX Handler 并沒有想象中快, 尤其是文件比較大的時候
          2. SAX Handler 編寫容易出錯, 因為需要區別不同的元素, 需要很多判斷才能拿到自己想要的信息
          3. 沒有統一的方法獲取SAX Handler解析出來的信息
          這實際上反映了目前SAX Handler接口定義中缺失的三種能力: Stoppable, Subscribable, 和 Reportable

          1, Stoppable


          缺省情況下SAX Parser會解析整個文件, 即使你已經取得了足夠的你想要的信息, 但解析不會停止, 這就是感覺SAX Parser在解析大文件的時候不是很快的原因

          只有異常才能阻止SAX Parser繼續解析, 所以解決方法很簡單:

          a). 定義接口:

          public interface Stoppable {

              boolean canStop();

          }

          b). 缺省實現:

          public abstract class EnhancedHandler extends DefaultHandler implements Reportable {

              private boolean canStop;

              public boolean canStop() {  return canStop;    }

              protected void stop() { canStop = true; }  //call this method whensubclass objects get enough information.

          }

          c). 當且只當所有SAX Handler都可以停止的時候, 拋出異常:

          public class CompositeEnhancedHandler extends DefaultHandler {

              private static final RuntimeException SHOULD_STOP_EXCEPTION = newShouldStopParsingException();

              private final EnhancedHandler[] handlers;

              publicCompositeEnhancedHandler(EnhancedHandler... handlers) {

                  this.handlers = handlers;

              }

              public void characters(char[] ch, int start, int length) throws SAXException {

                  for (EnhancedHandler handler : handlers) { handler.characters(ch, start,length); }

                  throwExceptionIfCanStop();

              }

              public void endElement(String uri, String localName,String qName) throws SAXException {

                  for (EnhancedHandler handler : handlers) { handler.endElement(uri, localName,qName); }

                  throwExceptionIfCanStop();

              }

              public void startElement(String uri, String localName,String qName, Attributes attributes) throws SAXException {

                  for (EnhancedHandler handler : handlers) { handler.startElement(uri,localName, qName, attributes); }

                  throwExceptionIfCanStop();

              }

              private void throwExceptionIfCanStop() {

                  for (EnhancedHandler handler : handlers) {  if (!handler.canStop()) { return; } }

                  throw SHOULD_STOP_EXCEPTION;

              }

          }

          d). SAX Parser 捕獲異常:

          CompositeEnhancedHandler handler = newCompositeEnhancedHandler(new Handler1(), new Handler2());

          try {

              SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();

              saxParser.parse(new File("england.xml"), handler);

          } catch (ShouldStopParsingException se) {

              // All handlers got enough information, just stop parsing.

           

          2. Subscribable


          不能指定只處理特定元素的能力的缺乏, 使得SAX Handler難以編寫且易于出錯,  不得不判斷當前元素的名稱, 是否正在處理特定的元素等, 這使得每個Handler都在重復這些邏輯相似的代碼.

          解決方法是提供一個額外的中間層, 詢問SAX Handler對哪個元素感興趣. 該中間層只會向每個SAX Handler發送它們感興趣的元素信息. (也可以采用每個SAX Handler向中間層注冊感興趣信息的方法, 但比較復雜, ESAX采用前者)

          a). 定義接口:

          public interface Subscribable {

              String subscribe();

          }


          b). 中間層 CompositeEnhancedHandler:

          public class CompositeEnhancedHandler extends DefaultHandler{

              private final AddableMap mapping = new AddableMap();

              private List<EnhancedHandler> currentHandlers;

              publicCompositeEnhancedHandler(EnhancedHandler... handlers) {

                  ... ...

                  for (EnhancedHandler handler : handlers) {  mapping.get(handler.subscribe()).add(handler); }

              }

              public void startElement(String uri, String localName,String qName, Attributes attributes) throws SAXException {

                  currentHandlers = mapping.get(qName);

                  for (EnhancedHandler handler : currentHandlers) { handler.startElement(uri,localName, qName, attributes); }

                  ... ...

              }

              public void characters(char[] ch, int start, int length) throws SAXException {

                  for (EnhancedHandler handler : currentHandlers) { handler.characters(ch, start,length); }

                  ... ...

              }

           

              public void endElement(String uri, String localName,String qName) throws SAXException {

                  for (EnhancedHandler handler : currentHandlers) { handler.endElement(uri, localName,qName); }

                  ... ...

              }

              private static class AddableMap {

                  private Map<String, List<EnhancedHandler>>container = new HashMap<String, List<EnhancedHandler>>();

                  public List<EnhancedHandler>get(String qname) {

                      if (!container.containsKey(qname)) { container.put(qname, new ArrayList<EnhancedHandler>()); }

                      return container.get(qname);

                  }

              }

          }

           

          3. Reportable


          DOM提供了很方便的方法供提取特定信息, 但SAX Handler缺失了這項能力,  感興趣的信息被藏在每個Handler內部

          ESAX提供的解決方法是"收集參數模式"

          a). 定義接口:

          public interface Reportable {

              void report(Map resultSet);

          }

          b). 缺省支持:

          public abstract class EnhancedHandler extends DefaultHandler implements Reportable,Stoppable, Subscribable {

              ... ...

          }

          public class CompositeEnhancedHandler extends DefaultHandler implements Reportable{

              public void report(Map resultSet) {

                  for (EnhancedHandler handler : handlers) { handler.report(resultSet); }

              }

          }



          最終, ESAX 為 原始的 SAX Handler 補足了 可中止的能力, 可訂閱的能力, 可匯報的能力, 使得比原始的SAX Handler更快, 比DOM接口更簡單, 更易于編程

          一個簡單的例子可參見:

          http://jade-stone-suite.googlecode.com/svn/trunk/JS.ESax/test/jade/stone/esax/sample/FACupHandler.java

          測試用例參見:

          http://jade-stone-suite.googlecode.com/svn/trunk/JS.ESax/test/jade/stone/esax/test/CompositeEnhancedHandlerTest.java


          最終的缺省實現可參見:

          http://jade-stone-suite.googlecode.com/svn/trunk/JS.ESax/src/jade/stone/esax/support/EnhancedHandler.java

          http://jade-stone-suite.googlecode.com/svn/trunk/JS.ESax/src/jade/stone/esax/support/CompositeEnhancedHandler.java

          項目主頁:

          http://jade-stone-suite.googlecode.com/svn/trunk/JS.ESax/



          評論

          # re: Enhanced SAX Handler :比 DOM 還簡單的 SAX Handler  回復  更多評論   

          2007-05-22 13:09 by bitiwyh
          看上去似乎不錯...
          學習一下.

          Stopable的樣例代碼有錯
          b). 缺省實現:

          public abstract class EnhancedHandler extends DefaultHandler implements Reportable {

          Stopable?

          不過,牛牛們都說,不能用異常控制流程啊......

          # re: Enhanced SAX Handler :比 DOM 還簡單的 SAX Handler  回復  更多評論   

          2007-05-22 15:38 by 切爾斯基
          有沒有不用異常的好方法推薦? 我找了半天沒找到, 除非自己寫 SAXParser.parse()了, 呵呵

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 克拉玛依市| 防城港市| 赤峰市| 屏山县| 时尚| 揭东县| 弥渡县| 哈密市| 青铜峡市| 荔波县| 庆城县| 古蔺县| 兰考县| 瑞金市| 北安市| 延庆县| 汝城县| 浦江县| 山丹县| 长沙县| 新营市| 甘泉县| 南汇区| 西平县| 镇雄县| 高雄县| 北安市| 东至县| 亚东县| 苍山县| 桂阳县| 临夏县| 乌审旗| 泰兴市| 泌阳县| 松滋市| 乐平市| 鹤壁市| 富阳市| 原平市| 永和县|