Java 高效地将多个大型xml文件合并为一个
我在网上搜索,上下搜索。没有解决办法。尽管我找到了在纯xslt中实现这一点的解决方案 但问题是,生成的xml将有几百MB大。所以我必须用Java中的SAX来实现这一点。(请不要使用xslt解决方案,尽管我用xslt标记了它;-)) 让我详细解释一下。我有几个应该解析的多个xml文件(最好是InputSteam)。文件或InputStream的 输入流1Java 高效地将多个大型xml文件合并为一个,java,xml,xslt,sax,stx,Java,Xml,Xslt,Sax,Stx,我在网上搜索,上下搜索。没有解决办法。尽管我找到了在纯xslt中实现这一点的解决方案 但问题是,生成的xml将有几百MB大。所以我必须用Java中的SAX来实现这一点。(请不要使用xslt解决方案,尽管我用xslt标记了它;-)) 让我详细解释一下。我有几个应该解析的多个xml文件(最好是InputSteam)。文件或InputStream的 输入流1 <root> <doc> <tag>test1</tag> </doc&g
<root>
<doc>
<tag>test1</tag>
</doc>
<doc>
<tag>test2</tag>
</doc>
...
</root>
或者我应该直接在ContentHandler中解析InputStreams吗?您可能想看看Saxon的付费版本。它可以动态处理XSLT,而不需要在内存中使用完整的DOM。我自己也没有这样做过,但我记得看过一篇IBM developerworks文章,这篇文章似乎让这变得非常简单 现在有点旧了,试试看
这是StAX而不是SAX。我不确定当前的jdk是否包含StAX。如果没有,您可能可以从中获得它。我最终通过以下代码片段实现了这一点:
finalHandler = new StreamResult(new OutputStreamWriter(System.out));
// customHandler extends DefaultHandler
CustomTransformerHandler customHandler = new CustomTransformerHandler(
finalHandler);
customHandler.startDocumentExplicitly();
InputStream is = null;
while ((is = customHandler.createNextInputStream()) != null) {
// multiple inputStream parsing
XMLReader myReader = XMLReaderFactory.createXMLReader();
myReader.setContentHandler(customHandler);
myReader.parse(new InputSource(is));
}
customHandler.endDocumentExplicitly();
重要的部分是将startDocument和endDocument方法保留为空。所有其他方法(字符、startElement、endElement)将重定向到finalHandler。如果读取所有inputstreams,customHandler.createNextInputStream方法将返回null。合并文件的最有效方法是使用AFAIK提供的字节级剪切和粘贴功能。您获取这两个文件,将它们解析为VTDNav对象,然后实例化一个XMLModifier对象,从第二个文件中获取片段,并将它们插入第一个文件。。。这比SAX要有效得多。。此外,生成的XML会将写入方向写入文件——不需要将其存储在内存中。下面是不到20行的完整代码
import com.ximpleware.*;
import java.io.*;
public class merge {
// merge second.xml into first.xml assuming the same encoding
public static void main(String[] s) throws VTDException, IOException{
VTDGen vg = new VTDGen();
if (!vg.parseFile("d:\\xml\\first.xml", false))
return;
VTDNav vn1=vg.getNav();
if(!vg.parseFile("d:\\xml\\second.xml", false))
return;
VTDNav vn2 = vg.getNav();
XMLModifier xm = new XMLModifier(vn1);
long l = vn2.getContentFragment();
xm.insertBeforeTail(vn2, l);
xm.output("d:\\xml\\merged.xml");
}
}
嗯,在xslt中,无论您在哪里,都可以查找第一个节点和最后一个节点。Ie:一切都需要在记忆中。。。根据xslt的定义。或者你怎么想?有相当大的XSLT程序子集,你不需要在内存中使用完整的DOM树来执行。hmmh,但我不想在内存中使用它们。。。只需将它们直接导入光盘即可。我不明白这怎么会比sax快。感谢vtd xml提示。它看起来很有希望(从我在sourceforge网站上看到的内容来看)。但尽管它可能快100倍。如果它需要文档的100%RAM(甚至更多),我就不能使用它:可能是生成的xml甚至无法放入内存。请注意,张先生是VTD-xml的作者。+1 JDK包括StAX,因为据我所知是1.5。使用起来比SAX方便得多。
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
xmlReader.setContentHandler(customHandler);
xmlReader.parse(getInputSource()); // only one InputStream possible
finalHandler = new StreamResult(new OutputStreamWriter(System.out));
// customHandler extends DefaultHandler
CustomTransformerHandler customHandler = new CustomTransformerHandler(
finalHandler);
customHandler.startDocumentExplicitly();
InputStream is = null;
while ((is = customHandler.createNextInputStream()) != null) {
// multiple inputStream parsing
XMLReader myReader = XMLReaderFactory.createXMLReader();
myReader.setContentHandler(customHandler);
myReader.parse(new InputSource(is));
}
customHandler.endDocumentExplicitly();
import com.ximpleware.*;
import java.io.*;
public class merge {
// merge second.xml into first.xml assuming the same encoding
public static void main(String[] s) throws VTDException, IOException{
VTDGen vg = new VTDGen();
if (!vg.parseFile("d:\\xml\\first.xml", false))
return;
VTDNav vn1=vg.getNav();
if(!vg.parseFile("d:\\xml\\second.xml", false))
return;
VTDNav vn2 = vg.getNav();
XMLModifier xm = new XMLModifier(vn1);
long l = vn2.getContentFragment();
xm.insertBeforeTail(vn2, l);
xm.output("d:\\xml\\merged.xml");
}
}