XOM规范化需要太长时间

时间:2012-11-25 15:44:08

标签: java xml performance canonicalization xom

我有一个可以大到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文档中的段以及整个文档本身。因此,使用文档本身作为参数对我不起作用。

最佳

3 个答案:

答案 0 :(得分:1)

memory is not restriction

memory is not restriction

main thread is green and no blocking

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

Nodes.contains is the most busy one

内部节点在List中进行管理,并进行线性比较。 列表中的更多项目,“包含”将更慢。

private final List nodes;
public boolean contains(Node node) {
    return nodes.contains(node);
}

所以

  • 尝试修改lib的代码以使用HashMap来保存节点。
  • 或使用多线程来利用更多的CPU,如果你的XML可以分成小的xmls。

工具: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 APIApache 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")));

结果

graphic result

下面是一个以秒为单位的结果表。测试进行了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