2013-12-10 28 views
1

我已經實現了拉解析器,它讀取數據流並通過回調處理程序在選定內容上發出令牌。這種抽象技術也被稱爲觀察者模式(回調處理程序也被稱爲觀察者),並在SAX中用於解析XML。如何在推解析器和拉解析器之間進行映射

相反的設計模式(是否有一個名稱?)是拉動下一個數據標記,例如在使用StAX進行XML解析時使用。

// push 
parser.parse(callback: handler); 

// pull 
while(token = parser.next) { 
    handler(token) 
} 

但我怎麼映射推解析器拉解析器:

人們可以通過循環拉解析器很容易地映射到一推解析器?

+0

我不完全明白你在問,但我最初的想法是推拉術語只是定義。算法總是接受輸入併產生輸出。所以在這種情況下,從數據流中提取並推入令牌的反面會拉動令牌並推送數據流。 AFAIK拉動推送數據的算法是沒有意義的,就像談論從輸出生成輸入的算法是沒有意義的。 –

回答

1

我認爲你正在尋找的是控制反轉,這在與類似堆棧的執行模型相關的語言中是不容易的。

C不完全焊接到執行堆棧,因此您可以使用(不建議使用)Posix getcontext/setcontext/makecontext或稍微更易移植的線程來執行此操作。

在其他語言中,如果沒有較少的思維彎曲,則更容易。請參閱Scheme的call/cc原語,這段Lua ancient history,或者看一看Python生成器(儘管後者在沒有來自其控制將被反轉的函數的幫助下不能夠反轉控制)。

2

爲了適應推式解析器到一個pull語法分析器中,您必須收集幾個(全部?取決於正在分析的內容以及被推入的元素的順序)到Event對象中。然後允許那些Event被拉。

我們可以使用XML作爲示例,並將SAXHandler調整爲StAX解析器。我們還必須實現用於迭代StAX XMLEvent的XMLStreamReader方法。

我從來沒有使用StAX,但它看起來像將當前狀態存儲在XMLStreamReader對象中。每次調用reader.next()更新狀態,並從reader.getName()reader.getText()等等返回的值相應更新。

我們可以通過幾種方法從先分析內存中的所有內容開始,然後迭代我們存儲在內存中的內容,再到更復雜的技術,例如使用多線程分析XML並阻止讀取下一個標記,直到用戶呼叫next()

爲了簡單起見,我將只是顯示在內存中StAX的方法存儲的一切現在

class SAXHandler extends DefaultHandler implements XMLSTreamReader { 

     //Stax Event objects 
     List<XMLEvent> events = new ArrayList<>; 
     int counter=0; 
     //Stax current tag name and text data updated with calls to next() 
     private String name, text; 


     @Override 
     //Triggered when the start of tag is found. 
     public void startElement(String uri, String localName, 
         String qName, Attributes attributes) 
         throws SAXException { 

      //create a new XMLEvent for the start of the new tag 
      XMLEvent newEvent = .... 

      events.add(newEvent); 


     } 
     //other SAX methods implemented similarly 
     ... 

@Override 
    public XMLEvent next(){ 
     if(!hasNext()){ 
      throw NoSuchElementException(); 
     } 
     counter++; 
     XMLEvent next =events(counter); 
     //update our content 
     this.name = next.name; 
     this.text = next.text; 
     ... 
     return next; 
    } 

    @Override 
    public boolean hasNext(){ 
     return counter < events.size(); 
    } 

    ... 
    @Override 
    public String getName(){ 
      return name; 
    } 
    @Override 
    public String getText(){ 
      return text; 
    } 
} 

希望這有助於

+0

感謝您的詳細示例。爲了獲取事件列表,預先解析所有事情並不是有效的選擇,所以我想我必須深入研究多線程。 – Jakob

+0

我以前做過,它非常容易出錯。使用我的例子,你可以用'new LinkedBlockingQueue (1)'代替'new ArrayList ',這將強制線程執行SAX解析,如果已經存在的列表中已經包含了某些東西。並改變'next()'來阻止使用'take()'彈出列表。但是,那麼你不得不擔心處理文件的結尾(沒有別的東西需要,所以你必須停止阻止)。和錯誤處理,如果你從來沒有完成解析文件somereason(IO異常,或用戶停止調用next()之前完成等) – dkatzel