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



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

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

通过循环一个pull解析器可以很容易地映射到push解析器:

// push
parser.parse( callback: handler );
// pull
while( token = parser.next ) {
    handler(token)
}

但是,我如何将推式解析器映射到拉式解析器呢?

要将推送解析器转换为拉式解析器,必须将多个(全部?取决于要解析的内容和要推送的元素的顺序)收集到Event对象中。然后允许这些Event被拉出。

我们可以使用XML作为示例,并将SAXHandler改编为StAX解析器。我们还必须实现XMLStreamReader的方法,以便在StAX XMLEvent s上进行迭代。

我从未使用过StAX,但它似乎将当前状态存储在XMLStreamReader对象中。对CCD_ 5的每次调用都会更新状态,并且来自CCD_ 6和CCD_。

我们可以通过多种方式来做到这一点,从首先解析内存中的整个内容,然后迭代存储在内存中的内容,到更复杂的技术,例如使用多个线程来解析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;
    }
 }

希望这能帮助

我认为您正在寻找的是控制反转,这在与堆栈式执行模型绑定的语言中并不容易。

C并没有完全焊接到执行堆栈上,所以您可以使用(不推荐使用的)Posix getcontext/setcontext/makecontext,或者使用线程来实现这一点。

在其他语言中,这更容易,即使同样令人费解。请参阅Scheme的call/cc原语,这是Lua的古老历史,或者看看Python生成器(尽管后者在没有要反转控制的函数的帮助的情况下无法反转控制)

最新更新