Parsing an XML stream with no root element
我需要解析一个连续的格式良好的XML元素流,只给我一个已经构造好的
使用JavaEDCX1的2个类不起作用,因为XML读取器期望解析封闭格式的XML,从封闭的根元素开始。所以,它只读取流中的第一个元素,它将其视为根,并在下一个元素中失败,典型的
org.xml.sax.SAXParseException: The markup in the document following the root element must be well-formed.
对于不包含根元素的文件,但如果该元素确实存在或可以定义(并称为myrootelement),则可以执行以下操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | Strint path = <the full path to the file>; XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); StringBuilder buffer = new StringBuilder(); buffer.append("<?xml version="1.0"?> "); buffer.append("<!DOCTYPE MyRootElement"); buffer.append("[<!ENTITY data SYSTEM "file:///"); buffer.append(path); buffer.append("">]> "); buffer.append("<MyRootElement xmlns:...> "); buffer.append("&data; "); buffer.append("</MyRootElement> "); InputSource source = new InputSource(new StringReader(buffer.toString())); xmlReader.parse(source); |
我已经通过将部分
本质上,我在寻找"零碎的XML解析"。所以,我的问题是,是否可以使用标准的Java API(包括EDCOX1的5)和EDCOX1(6个)包来完成?
Sequenceinputstream来救援:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | SAXParserFactory saxFactory = SAXParserFactory.newInstance(); SAXParser parser = saxFactory.newSAXParser(); parser.parse( new SequenceInputStream( Collections.enumeration(Arrays.asList( new InputStream[] { new ByteArrayInputStream("<dummy>".getBytes()), new FileInputStream(file),//bogus xml new ByteArrayInputStream("</dummy>".getBytes()), })) ), new DefaultHandler() ); |
您可以将给定的
编辑:
虽然这与执行您自己的
其他提议的一个有趣的变化可能是实施一个
您可以编写自己的读卡器实现来封装给定的读卡器实例。这个新的阅读器应该像您在示例代码中所做的那样,提供头和根元素,然后提供来自底层阅读器的数据,最后提供结束根标记。通过这种方式,您可以向XML解析器提供有效的XML流,还可以使用传递给代码的reader对象。
您可以创建自己的读卡器,将其委托给提供的读卡器,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | final Reader reader = <whatever you are getting>; Reader wrappedReader = new Reader() { Reader readerCopy = reader; String start ="<?xml version="1.0"?><MyRootElement>"; String end ="</MyRootElement>"; int index; @Override public void close() throws IOException { readerCopy.close(); } @Override public int read(char[] cbuf, int off, int len) throws IOException { // You'll have to get the logic right here - this is only placeholder code if (index < start.length()) { // Copy from start to cbuf } int result = readerCopy.read(cbuf, off, len); if (result == -1) { // Copy from end } index += len; return result; } }; |
你必须填写逻辑,首先从
不过,这种方法是可行的。
只需插入虚拟根元素。我能想到的最优雅的解决方案是创建自己的inputstream或reader,当您第一次调用它的read()/readline()时,它包装常规inputsteam/reader并返回虚拟的
答案3是可行的,但对我来说,我必须从Sequenceinputstream创建一个inputsource的额外步骤。
1 2 3 4 5 6 7 8 9 10 11 | XMLReader xmlReader = saxParser.getXMLReader(); xmlReader.setContentHandler((ContentHandler) this); // Trying to add root element Enumeration<InputStream> streams = Collections.enumeration( Arrays.asList(new InputStream[] { new ByteArrayInputStream("<TopNode>".getBytes()), new FileInputStream(xmlFile),//bogus xml new ByteArrayInputStream("</TopNode>".getBytes()), })); InputSource is = new InputSource(seqStream); xmlReader.parse(is); |