Смещения элементов и скрытый текст в dom4j

#xml #xml-parsing #dom4j

#xml #синтаксический анализ xml #dom4j

Вопрос:

Нам нужно обработать XML-файл, который содержит элементы PCDATA, подобные следующим:

 <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>
  

Для каждого <предложения> каждого <текста> нам нужно заполнить структуру данных, содержащую идентификатор предложения и полный текст, охватываемый предложением. Затем для каждого <экземпляра> нам нужно заполнить структуру данных, содержащую идентификатор экземпляра и его начальную и конечную позицию в предложении. (Нам все равно, нормализовано ли пустое пространство.)

Итак, для приведенного выше примера нам в основном нужно следующее:

 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 не подходит для этой задачи, какой инструмент лучше?

Ответ №1:

Это, безусловно, выполнимо, но требует небольшой работы. Вы могли бы создать посетителя, который отслеживает, где он находится в дереве, и накапливает смещения текста и экземпляра по мере продвижения. Однако это решение с тем же успехом может быть реализовано непосредственно обработчиком 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=%sn", attributes.getValue("id"));
        collecting = true;
        buf.setLength(0);
        ic = 0;
    } else if (localName.equals("instance")) {
          ic;
        System.out.printf("i%d.id=%sn", ic, attributes.getValue("id"));
        System.out.printf("i%d.start=%sn", 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=%sn", buf.toString());
    } else if (localName.equals("instance")) {
        System.out.printf("i%d.end=%sn", 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());
}
}