如何预览XMLStreamReader?

时间:2012-09-24 08:15:05

标签: java xml-parsing

我在XMLStreamReader文档中找不到任何peekunread函数。例如,为了解析HTML元素列表中的子元素列表,至少要获得一个令牌的首选方法是什么?

<ul>
  <li>
  <li>
</ul>

当我使用ulli的解析函数创建一个递归的正确解析器时,li解析函数必须在找到ul的结束标记时终止,但是它不能使用它,因为ul解析函数需要它才能成功。

我习惯用peekunread来解决这些问题,但似乎缺少这些问题。解决此问题的首选Java方法是什么?

更新:我使用XMLStreamReader实现了解析器而没有预见。

2 个答案:

答案 0 :(得分:2)

有一种实现递归解析器的常用方法,通过预先读取下一个令牌,存储它并对其进行测试,避免了对unreadpeek的需求:

  • 当您读入令牌时,将其存储在(全局)变量中。
  • 然后您只需使用您正在寻找的所有代币(例如<li></ul>
  • 对其进行测试
  • 当你找到合适的方法时,你可以调用处理该方法的方法(或继续)
  • (读取下一个标记,“消耗”匹配的标记)

实际上,你已经已经向前看。

Dragon编译器书的第1版有一个很好的例子,在他们的早期概述章节中,在C中(他们在第二版中使用Java,但它不必要地夸大其词,恕我直言 - C风格在Java中运行良好)

我将尝试从我自己的源代码中提取示例,但我的代码被分成一个库层,其中的处理方法更易于使用。我会尝试将它们结合起来做一个明确的例子,但它可能不会独立运行。把它想象成伪代码,来说明这个想法,你需要填补空白。

XMLStreamReader in; 
int token;
String localname;

public void parse() {
  next();
  if (token==START_ELEMENT && localname.equals("ul")) ul();
}

void ul() {
  next();          // assume we are called when a <ul> is seen, so we consume it
  while (true) {   // loops for list
    if (token==START_ELEMENT && localname.equals("li")) li();  // ifs for choice 
    else if (token==START_ELEMENT && localname.equals("sometag")) sometag();
    else break;
  }
  if (token==END_ELEMENT && localname.equals("ul")) next();
  else throw new RuntimeException("expected </ul>");
       // <li> or <sometag> would also be acceptable
}

void li() {
  next();
  ...
}

void next() {
  token = in.next();         // consume the token means to set up the next one
  localname = in.getLocalName();
}

如果您创建一个图层库来处理重复的内容,我发现它更容易使用,例如我有:

  • boolean startTag(String name)只要匹配
  • 就返回true
  • void requireStartTag(String name)如果匹配则消耗,否则抛出异常

但我认为这个例子更清晰,保持一切文字。

还有其他问题,比如跳过非元素令牌(如评论,PI等);跟踪您所在的行以获得更多有用的例外等。

答案 1 :(得分:1)

似乎没有直截了当的做法。您是否可以使用XMLEventReader来完成相同的功能?