2013-12-10 23 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