我有一个可以大到1GB的XML文件。我正在使用XOM来避免OutOfMemory Exceptions。
我需要规范化整个文档,但规范化需要很长时间,即使对于1.5 MB文件也是如此。
这就是我所做的:
我有这个示例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();
}
即使这个代码适用于小文件,规范化部分在我的开发环境(4gb ram,64bit,eclipse,windows)上的1.5mb文件大约需要7分钟
非常感谢任何有关此延迟原因的指示。
PS。我需要规范化整个XML文档中的段以及整个文档本身。因此,使用文档本身作为参数对我不起作用。
最佳
答案 0 :(得分:1)
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
内部节点在List中进行管理,并进行线性比较。 列表中的更多项目,“包含”将更慢。
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
答案 1 :(得分:0)
由于您希望序列化整个文档,因此可以直接替换
Nodes nodes = doc.getRootElement().query("./descendant-or-self::node()|./@*");
outputter.write(nodes);
与
outputter.write(doc);
在给定节点列表而不仅仅是根节点进行规范化时,看起来Canonicalizer
做了额外的工作(例如whunmr提到的nodes.contains()
调用)。
如果这不起作用或者不够,我会分叉Canonicalizer
并按照分析的建议进行优化。
答案 2 :(得分:0)
如果您愿意放弃XOM,我可能会解决您的问题。我的解决方案包括使用XPath API和Apache Santuario。
性能差异令人印象深刻,但我认为提供比较会很好。
对于测试,我使用了您在问题中提供的1.5MB的XML文件。
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();
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 4GB内存
SO:Debian 6.0 64bit
Java:OpenJDK 1.6.0_18 64bit
XOM:1.2.8
Apache Santuario:1.5.3