Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parsing 如何在推式解析器和拉式解析器之间映射_Parsing_Design Patterns_Observer Pattern - Fatal编程技术网

Parsing 如何在推式解析器和拉式解析器之间映射

Parsing 如何在推式解析器和拉式解析器之间映射,parsing,design-patterns,observer-pattern,Parsing,Design Patterns,Observer Pattern,我已经实现了一个pull解析器,它读取数据流并通过回调处理程序对所选内容发出令牌。这种抽象技术也称为观察者模式(回调处理程序也称为观察者),例如在SAX中用于解析XML 相反的设计模式(是否有名称?)是提取下一个数据令牌,例如在使用StAX进行XML解析时使用的数据令牌 通过循环pull解析器,可以轻松映射到push解析器: // push parser.parse( callback: handler ); // pull while( token = parser.next ) {

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

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

通过循环pull解析器,可以轻松映射到push解析器:

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

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

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

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

C并没有完全焊接到执行堆栈上,所以您可以使用(不推荐使用的)Posix实现这一点,或者使用线程实现更高的可移植性


在其他语言中,这是更容易的,如果不减少思维弯曲。请参阅Scheme的
call/cc
原语,这段Lua,或者看看Python生成器(尽管后者无法在没有要反转控件的函数的帮助下反转控件)。

要将推式解析器调整为拉式解析器,您必须收集几个(全部?取决于被解析的内容和被推送元素的顺序)放入
Event
对象中。然后允许拉取这些
Event
s

我们可以以XML为例,将SAXHandler改编成StAX解析器。我们还必须实现XMLStreamReader在StAX
XMLEvent
s上迭代的方法

我从未使用过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
      ...
类SAXHandler扩展DefaultHandler实现XMLSTreamReader{
//Stax事件对象
列表事件=新的ArrayList;
int计数器=0;
//Stax当前标记名和文本数据随对next()的调用而更新
私有字符串名称、文本;
@凌驾
//在找到标记的开始时触发。
public void startElement(字符串uri、字符串localName、,
字符串(名称、属性)
抛出SAX异常{
//为新标记的开头创建一个新的XMLEvent
XMLEvent newEvent=。。。。
events.add(newEvent);
}
//其他SAX方法的实现类似
...
现在,对于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;
    }
 }
@覆盖
公共XMLEvent下一步(){
如果(!hasNext()){
抛出NoTouchElementException();
}
计数器++;
XMLEvent next=事件(计数器);
//更新我们的内容
this.name=next.name;
this.text=next.text;
... 
下一步返回;
}
@凌驾
公共布尔hasNext(){
返回计数器

希望这有帮助

我不完全理解你的要求,但我最初的想法是术语push和pull只是定义。算法总是接受输入并产生输出。因此,在这种情况下,从数据流中提取并推送令牌的相反方式是提取令牌并推送数据流。请看一个算法pulling推送数据没有意义,就像谈论从输出生成输入的算法没有意义一样。感谢详细的示例。仅为获取事件列表而预解析所有内容不是有效的选择,因此我想我必须深入研究多线程。我以前做过,而且非常容易出错。使用我的示例,您可以可以使用
新的LinkedBlockingQueue(1)
替换
新的ArrayList
,这将强制执行SAX解析的线程在列表中已有内容时进行阻止。并将
下一步()
更改为使用
take()
阻止弹出列表。但是,您必须担心处理文件结尾(没有其他需要采取的措施,因此您必须停止阻塞)。如果由于某种原因(IO异常或用户在完成下一步()之前停止调用等)而从未完成对文件的解析,则会出现错误处理