SAX: как получить содержимое элемента

у меня есть некоторые проблемы с пониманием синтаксического анализа XML-структур с SAX. Допустим, существует следующий XML:

<root>
  <element1>Value1</element1>
  <element2>Value2</element2>
</root>

и строковая переменная myString.

просто пройти через методы startElement, endElement() и characters() легко. Но я не понимаю, как я могу достичь следующего:

если текущий элемент равен element1 сохранять его значение value1 на myString. Насколько я понимаю, ничего нет. например:

if (qName.equals("element1")) myString = qName.getValue();

думаю, я просто думаю слишком сложно :-)

Роберт

3 ответов


С SAX вам нужно поддерживать свой собственный стек. Вы можете сделать что-то вроде этого для очень простой обработки:

void startElement(...) {
    if (name.equals("element1")) {
        inElement1 = true;
        element1Content = new StringBuffer();
    }
}

void characters(...) {
    if (inElement1) {
        element1Content.append(characterData);
    }
}

void endElement(...) {
    if (name.equals("element2")) {
        inElement1 = false;
        processElement1Content(element1Content.toString());
    }
}

Если вы хотите код, как в вашем примере, вам нужно использовать Модель DOM, а не SAX. DOM легче кодировать, но, как правило, медленнее и дороже памяти, чем SAX.

Я рекомендую использовать стороннюю библиотеку, а не встроенные библиотеки Java XML для манипулирования DOM. Dom4J кажется довольно хорошим, но, вероятно, есть и другие библиотеки там тоже есть.


Это решение работает для одного элемента с текстовым содержимым. Когда element1 имеет больше подэлементов, требуется дополнительная работа. Замечание Брайана очень важно. Если у вас несколько элементов или вам нужно более общее решение, это может вам помочь. Я тестировал его с помощью xml-файла 300+MB, и он все еще очень быстрый:

final StringBuilder builder=new StringBuilder();
XMLReader saxXmlReader = XMLReaderFactory.createXMLReader();

DefaultHandler handler = new DefaultHandler() {
    boolean isParsing = false;

    public void startElement(String uri, String localName, String qName, Attributes attributes) {
        if ("element1".equals(localName)) {
            isParsing = true;
        }
        if (isParsing) {
            builder.append("<" + qName + ">");
        }
    }

    @Override
    public void characters(char[] chars, int i, int i1) throws SAXException {
        if (isParsing) {
            builder.append(new String(chars, i, i1));
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if (isParsing) {
            builder.append("</" + qName + ">");
        }
        if ("element1".equals(localName)) {
            isParsing = false;
        }
    }
};

saxXmlReader.setContentHandler(handler);
saxXmlReader.setErrorHandler(handler);

saxXmlReader.parse(new InputSource(new FileInputStream(input)));

вы должны записать содержимое через characters() добавьте к StringBuilder для каждого вызова и только объединенное значение при endElement() звонок.

почему ? Потому что characters() можно назвать несколько раз для содержимого элемента - каждый вызов, ссылающийся на последовательную подпоследовательность этого текстового элемента.