【问题标题】:Parsing XML without document start and end tags解析没有文档开始和结束标签的 XML
【发布时间】:2013-02-03 13:59:12
【问题描述】:

我正在解析一个无法使用 SAX 解析器从 Internet 更改的文档。当文档格式如下时,它工作得很好:

<outtertag>
  <innertag>data</innertag>
  <innerag>moreData</innertag>
</outtertag>

但是,在某些调用中,我会在没有外部标签的情况下格式化 XML,所以我基本上只得到一个数据列表,如下所示:

  <innertag>data</innertag>
  <innerag>moreData</innertag>

这对我来说似乎很愚蠢,但我无法选择 XML 的格式,而且目前无法更改。问题在于,SAX 解析器似乎在遇到第一个关闭内部标签时就命中了 endDocument 事件。

我有一个相当老套的解决方案,将 InputStream 转换为 String,在其周围添加标签,然后将其转换回 InputStream。它实际上以这种方式解析得很好。但是,肯定有更好的方法。我也不想写一个完整的解析器。除了缺少开始和结束标签之外,大多数标签都是相同的。

顺便说一句,我将发布代码,但它是非常标准的 SAX 解析器。原文其实是解析了30个左右的一些标签:

        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser saxParser = factory.newSAXParser();
        XMLReader xmlReader = saxParser.getXMLReader();

        MyHandler handler = new MyHandler();
        xmlReader.setContentHandler(handler);

        InputSource inputSource = new InputSource(url.openStream());
        xmlReader.parse(inputSource);
    }

    catch (SAXException e) { e.printStackTrace(); } 
    catch (ParserConfigurationException e) { e.printStackTrace(); }
    catch(Exception e) { e.printStackTrace(); }
}

private class MyHandler extends DefaultHandler {
    private StringBuilder content;

    public MyHandler() {
        content = new StringBuilder();
    }
    public void startElement(String uri, String localName, String qName, 
            Attributes atts) throws SAXException {
        content = new StringBuilder();
        if(localName.equalsIgnoreCase("innertag")) {
            //Doing stuff
        }

    }
    public void endElement(String uri, String localName, String qName) 
            throws SAXException {

        //Doing stuff
    }
    public void characters(char[] ch, int start, int length) 
            throws SAXException {
        content.append(ch, start, length);
    }
    public void endDocument() throws SAXException {
               //When parsing the second type of document, hits this event almost immediately after parsing first tag



    }
}

而且,如果重要的话,这是我正在使用的 hacky 代码,但感觉不对,但它确实有效:

BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
        StringBuilder sb = new StringBuilder("<tag>");
        String line = null;

        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }           
        sb.append("</tag>");
        String xml =sb.toString();

        InputStream is = new ByteArrayInputStream(xml.getBytes());
        InputSource source = new InputSource(is);
        xmlReader.parse(source);

【问题讨论】:

  • 从技术上讲,如果它不符合 XML 标准,那么它就真的不是 XML。所以这不是不能选择格式,而是你没有得到 XML 文件,只是看起来像 XML 的东西,这就是解析器无法处理它的原因。
  • 关于如何解析第二组非 XML 数据的任何想法?
  • 我对 Java 不是很好,所以我不确定是否有特定于语言的解决方案,但在处理其他语言的类似情况时,我已经完成了你正在做的事情。
  • 我并不提倡这样做......但如果数据足够简单(没有 xml cmets、没有属性、没有嵌套标签等),也许是 RegEx?

标签: java android xml


【解决方案1】:

我想说的是,你现在所做的事情已经达到了最好的水平。需要考虑改进的一件事是流 -> 字符串 -> 流转换,尤其是在文档很大的情况下。您可以使用像 Guava 的 ByteStreams.join() 这样的东西,它可以让您将流连接在一起而不是字符串。类似于以下内容:

import com.google.common.io.*;
import java.io.*;

public class ConcatenateStreams {
    public static void main(String[] args) throws Exception {
        InputStream malformedXmlContent = externalXmlStream();
        InputSupplier<InputStream> joined = ByteStreams.join(
                inputSupplier("<root>"),
                inputSupplier(malformedXmlContent),
                inputSupplier("</root>"));
        ByteStreams.copy(joined, System.out);
    }

    private static InputStream externalXmlStream() {
        return new ByteArrayInputStream("<foo>5</foo><bar>10</bar>".getBytes());
    }

    private static InputSupplier<InputStream> inputSupplier(final String text) {
        return inputSupplier(new ByteArrayInputStream(text.getBytes()));
    }

    private static InputSupplier<InputStream> inputSupplier(final InputStream inputStream) {
        return new InputSupplier<InputStream>() {
            @Override
            public InputStream getInput() throws IOException {
                return inputStream;
            }
        };
    }
}

哪个输出:

<root><foo>5</foo><bar>10</bar></root>

【讨论】:

  • 是的,只需要确保所有流的编码都匹配。
【解决方案2】:

您拥有的 XML 不是格式良好的文档,但它是格式良好的外部解析实体,这意味着可以通过实体引用从格式良好的文档中引用它。所以创建一个这样的骨架文档:

<!DOCTYPE doc [
<!ENTITY e SYSTEM "data.xml">
]>
<doc>&e;</doc>

其中 data.xml 是您的 XML,并将此文档传递给 XML 解析器以代替原始文档。胜过编写数十行 Java 代码。

【讨论】:

    猜你喜欢
    • 2016-04-17
    • 1970-01-01
    • 1970-01-01
    • 2012-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多