问题 在JAVA中解析大型XML文档


我有以下问题:

我有一个XML文件(大约1GB),并且必须上下迭代(即不顺序;一个接一个地),以便获得所需的数据并对其进行一些操作。最初,我使用了DOM Java包,但显然,在解析XML文件时,JVM会达到其最大堆空间并停止。

为了克服这个问题,我提出的解决方案之一是找到另一个迭代XML中每个元素的解析器,然后将它的内容存储在硬盘上的临时SQLite数据库中。因此,通过这种方式,不会超出JVM的堆,并且一旦填满所有数据,我就会忽略XML文件并继续对临时SQLite数据库执行操作。

还有另一种方法可以解决我的问题吗?


6636
2018-02-28 09:53


起源

使用jaxb来解析xml - Biswajit
正如其他人所说,您需要使用SAX解析器而不是DOM解析器,它将完全满足您的需求。读这个: stackoverflow.com/questions/6828703/... - cowls
如果您无法保存整个DOM树,则必须找到按顺序进行处理的方法。那可能吗?你能展示出你所需要的XSLT吗? - Thorbjørn Ravn Andersen
对于解析大型xml文件,请始终使用SAX Parser。请参阅以下链接 堆栈溢出 - Yogesh Kulkarni
非顺序操作是什么意思? XML中是否存在不同的数据,并且它们之间存在交叉引用?无论使用哪种XML解析器,都必须将所有数据存储在内存中。宁 尝试给予更多 -Xmx 到JVM,它应该轻松处理1G。 - gaborsch


答案:


SAX(XML的简单API) 会帮助你。

与DOM解析器不同,SAX解析器不会创建内存   XML文档的表示,因此更快,使用更少   记忆。相反,SAX解析器会通知客户端XML文档   结构通过调用回调,即通过调用a上的方法    org.xml.sax.helpers.DefaultHandler 实例提供给解析器。

这是一个示例实现:

SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
DefaultHandler handler = new MyHandler();
parser.parse("file.xml", handler);

在哪里 MyHandler 定义生成文档/元素的开始/结束等事件时要采取的操作。

class MyHandler extends DefaultHandler {

    @Override
    public void startDocument() throws SAXException {
    }

    @Override
    public void endDocument() throws SAXException {
    }

    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
    }

    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
    }

    // To take specific actions for each chunk of character data (such as
    // adding the data to a node or buffer, or printing it to a file).
    @Override
    public void characters(char ch[], int start, int length)
            throws SAXException {
    }

}

12
2018-02-28 10:02



如果你曾经做过SAX解析,你可能知道 characters() 方法也很重要,你必须做一个 缓冲 字符数据,因为不能保证在一个块中处理内容数据(即两个 character() 呼叫可以立即完成)。我认为值得一提。 - gaborsch
我并不是说我的解决方案是完整的。这只是一个基本的实施。谢谢你指出。我会用那个更新我的答案。 - Nishant Shreshth
好的,谢谢,这样它就是+1 - gaborsch


如果你不想受到约束 记忆限制,我当然建议您使用当前的方法,并将所有内容存储在数据库中。

解析XML文件应该由a完成 SAX parser,每个人都推荐(包括我)。这样,您可以一次创建一个对象,并且可以立即将其持久保存到数据库中。

对于后处理(解析交叉引用),您可以使用 SELECT来自数据库,制作主键,索引等。如果您对此感到满意,也可以使用ORM(Eclipselink,Hibernate)。

实际上我并不是真的推荐SQLite,它更容易设置MySQL服务器,并将数据存储在那里。稍后您甚至可以重用XML数据(如果不删除)。


3
2018-02-28 11:30



我想知道有人可以相信设置整个数据库服务器而不是使用嵌入式数据库更容易,您只需要包含一个JAR文件而无需安装任何东西。我认为对于这个用例,单独的数据库服务器将是过度的。也许有一些其他很好的理由使用数据库服务器,但更容易设置?真? - vanje
@vanje我不是指甲骨文:)我们谈论的是MySQL。说真的,我不敢相信任何开发人员设置MySQL服务器都会有问题。 - gaborsch
我认为每个开发人员都应该能够执行Oracle和MySQL的基本安装。我同意你的观点,Oracle远比MySQL复杂。但这不是重点。您将MySQL与SQLite进行了比较,并表示MySQL将更容易设置。但你没有提到你的意见究竟更容易。 - vanje


如果你想使用比SAX更高级的方法,这可能是非常棘手的编程,你可以使用最新的Saxon-EE版本来查看流式XSLT转换。但是,您对于您正在进行的精确处理过于模糊,以了解这是否适用于您的特定情况。


1
2018-02-28 14:49





如果你需要一个资源友好的方法来处理非常大的xml试试这个: http://www.xml2java.net/xml-to-java-data-binding-for-big-data/ 它允许您以SAX方式处理数据,但具有获取高级事件(xml数据映射到java)的优势,并且能够直接在代码中处理这些对象。所以它结合了jaxb便利性和SAX资源友好性。


0
2018-02-20 15:35