我有一个可以大到1 1GB的XML文件。我使用XOM来避免OutOfMemory异常。
我需要规范化整个文档,但规范化需要很长时间,即使对于1.5MB的文件也是如此。
以下是我所做的工作:
我有这个示例XML文件,并通过复制Item节点增加了文档的大小。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Packet id="some" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Head>
<PacketId>a34567890</PacketId>
<PacketHeadItem1>12345</PacketHeadItem1>
<PacketHeadItem2>1</PacketHeadItem2>
<PacketHeadItem3>18</PacketHeadItem3>
<PacketHeadItem4/>
<PacketHeadItem5>12082011111408</PacketHeadItem5>
<PacketHeadItem6>1</PacketHeadItem6>
</Head>
<List id="list">
<Item>
<Item1>item1</Item1>
<Item2>item2</Item2>
<Item3>item3</Item3>
<Item4>item4</Item4>
<Item5>item5</Item5>
<Item6>item6</Item6>
<Item7>item7</Item7>
</Item>
</List>
</Packet>我用于规范化的代码如下:
private static void canonXOM() throws Exception {
String file = "D:\\PACKET.xml";
FileInputStream xmlFile = new FileInputStream(file);
Builder builder = new Builder(false);
Document doc = builder.build(xmlFile);
FileOutputStream fos = new FileOutputStream("D:\\canon.xml");
Canonicalizer outputter = new Canonicalizer(fos);
System.out.println("Query");
Nodes nodes = doc.getRootElement().query("./descendant-or-self::node()|./@*");
System.out.println("Canon");
outputter.write(nodes);
fos.close();
}尽管这段代码可以很好地处理小文件,但在我的开发环境(4 4gb ram、64位、eclipse、windows)上,1.5mb文件的规范化部分需要大约7分钟。
任何指向此延迟原因的提示都将不胜感激。
PS。我需要规范化来自整个XML文档以及整个文档本身的片段。因此,使用文档本身作为参数对我来说不起作用。
最好的
发布于 2012-12-05 18:37:49

memory is not restriction

main thread is green and no blocking. it is using as much cpu as it can.
because my machine has multi-cores , so the CPU total usage is not full.
But it will be full for a single CPU the main thread is running on.

Nodes.contains is the most busy one内部节点以列表的形式进行管理,并进行线性比较。列表中的项目越多,“包含”的速度就会变慢。
private final List nodes;
public boolean contains(Node node) {
return nodes.contains(node);
}所以
工具: JVisualVM。http://docs.oracle.com/javase/6/docs/technotes/guides/visualvm/index.html
发布于 2012-12-05 21:58:34
既然你想序列化整个文档,你能不能直接替换
Nodes nodes = doc.getRootElement().query("./descendant-or-self::node()|./@*");
outputter.write(nodes);使用
outputter.write(doc);当给出一个节点列表而不仅仅是一个要规范化的根节点时,看起来Canonicalizer做了额外的工作(比如whunmr提到的nodes.contains()调用)。
如果这不起作用或者还不够,我会派生Canonicalizer并按照性能分析的建议在那里进行优化。
发布于 2012-12-06 22:12:11
如果您愿意放弃XOM,我可能有一个解决您问题的方法。我的解决方案包括使用XPath API和Apache Santuario。
性能上的差异是令人印象深刻的,但我认为提供一个比较会很好。
对于测试,我使用了您在问题中提供的1.5MB的XML文件。
XOM测试
FileInputStream xmlFile = new FileInputStream("input.xml");
Builder builder = new Builder(false);
Document doc = builder.build(xmlFile);
FileOutputStream fos = new FileOutputStream("output.xml");
nu.xom.canonical.Canonicalizer outputter = new nu.xom.canonical.Canonicalizer(fos);
Nodes nodes = doc.getRootElement().query("./descendant-or-self::node()|./@*");
outputter.write(nodes);
fos.close();XPath/Santuario测试
org.apache.xml.security.Init.init();
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
org.w3c.dom.Document doc = builder.parse("input.xml");
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
org.w3c.dom.NodeList result = (org.w3c.dom.NodeList) xpath.evaluate("./descendant-or-self::node()|./@*", doc, XPathConstants.NODESET);
Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
byte canonXmlBytes[] = canon.canonicalizeXPathNodeSet(result);
IOUtils.write(canonXmlBytes, new FileOutputStream(new File("output.xml")));结果

下面是以秒为单位的结果表。测试进行了16次。
╔═════════════════╦═════════╦═══════════╗
║ Test ║ Average ║ Std. Dev. ║
╠═════════════════╬═════════╬═══════════╣
║ XOM ║ 140.433 ║ 4.851 ║
╠═════════════════╬═════════╬═══════════╣
║ XPath/Santuario ║ 2.4585 ║ 0.11187 ║
╚═════════════════╩═════════╩═══════════╝性能上的差异是巨大的,这与XML Path Language的实现有关。使用XPath/Santuario的缺点是它们不像XOM那么简单。
测试详细信息
计算机:英特尔酷睿i5 4 4GB内存
所以: Debian 6.0 64位
Java: OpenJDK 1.6.0_18 64位
XOM: 1.2.8
Apache Santuario: 1.5.3
https://stackoverflow.com/questions/13552555
复制相似问题