我正在使用SAX Parser解析我无法从互联网上更改的文档。当文档格式化时,它工作得很好:
<outtertag>
<innertag>data</innertag>
<innerag>moreData</innertag>
</outtertag>
但是,有些调用我在没有外部标记的情况下格式化XML,所以我基本上只得到一个数据列表,如:
<innertag>data</innertag>
<innerag>moreData</innertag>
这对我来说似乎很愚蠢,但我无法选择如何格式化XML,现在无法对其进行更改。问题是,当SAX Parser遇到第一次关闭时,它会立即触及endDocument事件。
我有一个相当hacky的解决方案,将InputStream转换为String,在其周围抛出标签,然后将其转换回InputStream。它实际上以这种方式解析。但是,肯定有更好的方法。我也不愿意写一个完整的其他解析器。除了缺少开关标签外,大多数标签都是相同的。
只是为了它,我会发布代码,但它是非常标准的SAX Parser。原文实际上解析了大约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);
答案 0 :(得分:1)
我会说你现在正在做的事情和你能得到的一样好。要考虑改进的一件事是流 - &gt; string - &gt;流转换,特别是如果文档很大。您可以使用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>
答案 1 :(得分:0)
您拥有的XML不是格式良好的文档,但它是一个格式良好的外部解析实体,这意味着它可以通过实体引用从格式良好的文档中引用。所以创建一个这样的骨架文档:
<!DOCTYPE doc [
<!ENTITY e SYSTEM "data.xml">
]>
<doc>&e;</doc>
其中data.xml是您的XML,并将此文档传递给XML解析器而不是原始文件。打败了几十行Java代码。