我已经实现了一个pull解析器,它通过回调处理程序读取数据流并在所选内容上发出令牌。这种抽象技术也称为观察者模式(回调处理程序也称为观察者),并在SAX中用于解析XML。
相反的设计模式(它有名称吗?)是拉下下一个数据令牌,例如用于使用StAX进行XML解析时。
通过循环拉解析器,可以轻松映射到推送解析器:
// push
parser.parse( callback: handler );
// pull
while( token = parser.next ) {
handler(token)
}
但是如何将推送解析器映射到拉解析器?
答案 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>