如何在推送解析器和拉解析器之间进行映射

时间:2013-12-10 21:46:29

标签: parsing design-patterns observer-pattern

我已经实现了一个pull解析器,它通过回调处理程序读取数据流并在所选内容上发出令牌。这种抽象技术也称为观察者模式(回调处理程序也称为观察者),并在SAX中用于解析XML。

相反的设计模式(它有名称吗?)是拉下下一个数据令牌,例如用于使用StAX进行XML解析时。

通过循环拉解析器,可以轻松映射到推送解析器:

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

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

但是如何将推送解析器映射到拉解析器?

2 个答案:

答案 0 :(得分:2)

要使推送解析器适应拉解析器,您必须将几个(所有?取决于正在解析的内容和被推送的元素的顺序)收集到Event个对象中。然后允许那些Event被拉。

我们可以使用XML作为示例,并将SAXHandler调整为StAX解析器。我们还必须实现XMLStreamReader的方法来迭代StAX XMLEvent

我从未使用过StAX,但看起来它将当前状态存储在XMLStreamReader对象中。每次调用reader.next()都会更新状态,并且reader.getName()reader.getText()等返回的值会相应更新。

我们可以通过以下几种方式来解析内存中的整个事物,然后迭代我们存储在内存中的内容,以及更复杂的技术,例如使用多个线程来解析XML并阻止读取下一个标记,直到用户来电next()

为简单起见,我只会将所有内容存储在内存中

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
      ...

现在对于StAX方法:

    @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;
    }
 }

希望这有帮助

答案 1 :(得分:1)

我认为您正在寻找的是Control Inversion,这在与堆栈式执行模型相关的语言中并不容易。

C并没有完全焊接到执行堆栈,所以你可以使用(不推荐使用的)Posix getcontext/setcontext/makecontext,或稍微更方便地使用线程。

在其他语言中,如果不是那么令人费解的话,它会更容易。请参阅Scheme的call/cc原语,这段Lua ancient history,或者看看Python生成器(尽管后者无法在没有控制权被反转的函数的帮助下反转控制。)< / p>