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()
можно назвать несколько раз для содержимого элемента - каждый вызов, ссылающийся на последовательную подпоследовательность этого текстового элемента.