SAX:如何获取元素的内容

时间:2010-11-07 21:45:42

标签: java xml sax

我在理解使用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();

猜猜我只是觉得太复杂了: - )

罗伯特

3 个答案:

答案 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看起来还不错,但也有其他库。