2

我有一个 1GB 大的 XML 文件。我正在使用 XOM 来避免 OutOfMemory 异常。

我需要规范化整个文档,但规范化需要很长时间,即使对于 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 文档以及整个文档本身的段进行规范化。因此,使用文档本身作为论据对我不起作用。

最好的

4

3 回答 3

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 是最忙的

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 可以拆分成小的 xml。

工具:JVisualVM。http://docs.oracle.com/javase/6/docs/technotes/guides/visualvm/index.html

于 2012-12-05T10:37:49.300 回答
0

Since you want the whole document serialized, can you just replace

Nodes nodes = doc.getRootElement().query("./descendant-or-self::node()|./@*");
outputter.write(nodes);

with

outputter.write(doc);

?

It looks like Canonicalizer does extra work (such as the nodes.contains() calls mentioned by whunmr) when given a node list instead of just a root node to canonicalize.

If that doesn't work or is not enough, I would fork Canonicalizer and make optimizations there as suggested by profiling.

于 2012-12-05T13:58:34.360 回答
0

如果您愿意放弃 XOM,我可能会解决您的问题。我的解决方案包括使用XPath APIApache Santuario

性能上的差异令人印象深刻,但我认为提供一个比较会很好。

对于测试,我使用了您在问题中提供的 XML 文件,大小为 1.5MB。

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 那样简单。

测试详情

机器:Intel Core i5 4GB RAM
SO:Debian 6.0 64bit
Java:OpenJDK 1.6.0_18 64bit
XOM:1.2.8
Apache Santuario:1.5.3

于 2012-12-06T14:12:11.190 回答