我实现了一个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生成器(尽管后者在没有要反转控制的函数的帮助的情况下无法反转控制)