0

我们需要处理一个包含 PCDATA 元素的 XML 文件,如下所示:

<corpus id="c01">
  <text id="t01>
    <sentence id="s01">Mary <instance id="i01">had</instance> a <instance id="i02">lamb</instance>.</sentence>
    <sentence id="s02">...</sentence>
    ...
  </text>
  ...
</corpus>

对于每个 <text> 的每个 <sentence>,我们需要填充一个包含句子 ID 和句子覆盖的全文的数据结构。然后,对于每个 <instance>,我们需要填充一个包含实例 ID 及其在句子中的开始和结束位置的数据结构。(我们不关心空白是否被规范化。)

所以对于上面的例子,我们基本上需要以下内容:

s.id = "s01"
s.text = "Mary had a lamb."
i1.id = "i01"
i1.start = 6
i1.end = 8
i2.id = "i02"
i2.start = 12
i2.end = 15

有没有办法用 dom4j 做到这一点?Element.getText() 方法跳过子元素的文本,我看不到任何方法可以给出一个元素在另一个元素中的偏移量。如果 dom4j 不适合这项任务,有什么更好的工具?

4

1 回答 1

0

这当然是可行的,但需要一些工作。您可以创建一个访问者来跟踪它在树中的位置并随着它的进展累积文本和实例偏移量。但是,该解决方案也可以直接由 SAX 处理程序实现,这样会快很多。

这应该给出一些开始:

public class Main extends DefaultHandler {

StringBuilder buf = new StringBuilder();
boolean collecting = false;
int ic = 0;

@Override
public void startElement(String uri, String localName, String qName,
        Attributes attributes) throws SAXException {
    if (localName.equals("sentence")) {
        System.out.printf("s.id=%s\n", attributes.getValue("id"));
        collecting = true;
        buf.setLength(0);
        ic = 0;
    } else if (localName.equals("instance")) {
        ++ic;
        System.out.printf("i%d.id=%s\n", ic, attributes.getValue("id"));
        System.out.printf("i%d.start=%s\n", ic, buf.length());
    }

}

@Override
public void endElement(String uri, String localName, String qName)
        throws SAXException {
    if (localName.equals("sentence")) {
        collecting = false;
        System.out.printf("s.text=%s\n", buf.toString());
    } else if (localName.equals("instance")) {
        System.out.printf("i%d.end=%s\n", ic, buf.length());
    }
}

@Override
public void characters(char[] ch, int start, int length)
        throws SAXException {
    if (collecting) {
        buf.append(ch, start, length);
    }
}

public static void main(String[] args) throws Exception {

    SAXParserFactory f = SAXParserFactory.newInstance();
    f.setNamespaceAware(true);
    f.newSAXParser().parse(Main.class.getResourceAsStream("data.xml"),
            new Main());
}
}
于 2011-10-25T14:49:35.397 回答