SAX: как получить содержимое элемента - PullRequest
6 голосов
/ 08 ноября 2010

У меня проблемы с пониманием синтаксического анализа структур 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 ]

9 голосов
/ 19 сентября 2012

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

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)));
6 голосов
/ 08 ноября 2010

С 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 выглядит довольно хорошо, но, вероятно, есть и другие библиотеки.

6 голосов
/ 08 ноября 2010

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

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

...