我在理解使用SAX解析XML结构时遇到了一些麻烦。假设有以下XML:
<root>
<element1>Value1</element1>
<element2>Value2</element2>
</root>
和一个String变量myString
。
使用方法startElement,endElement()和characters()很容易。但我不明白我如何能够实现以下目标:
如果当前元素等于element1
,则将其值value1
存储在myString
中。据我所知,没有什么比如:
if (qName.equals("element1")) myString = qName.getValue();
猜猜我只是觉得太复杂了: - )
罗伯特
答案 0 :(得分:9)
此解决方案适用于包含文本内容的单个元素。当element1有更多的子元素时,还需要做更多的工作。布莱恩的评论非常重要。 如果您有多个元素或想要更通用的解决方案,这可能对您有所帮助。我使用300 + MB xml文件对其进行了测试,但仍然非常快:
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)));
答案 1 :(得分:6)
您应该通过characters()
记录内容,为每次调用附加到StringBuilder,并仅在endElement()
调用时存储连接值。
为什么?因为characters()
可以为元素内容多次调用 - 每个调用引用该文本元素的连续子序列。
答案 2 :(得分:6)
使用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看起来还不错,但也有其他库。