在 JAVA 中解析大型 XML 文档
Posted
技术标签:
【中文标题】在 JAVA 中解析大型 XML 文档【英文标题】:Parsing large XML documents in JAVA 【发布时间】:2013-02-14 10:59:57 【问题描述】:我有以下问题:
我有一个 XML 文件(大约 1GB),并且必须向上和向下迭代(即不是连续的;一个接一个)以获得所需的数据并对其进行一些操作。最初,我使用 DOM Java 包,但很明显,在解析 XML 文件时,JVM 达到其最大堆空间并停止。
为了克服这个问题,我想出的一个解决方案是找到另一个解析器,它迭代 XML 中的每个元素,然后我将它的内容存储在我硬盘上的一个临时 SQLite 数据库中。因此,通过这种方式,不会超出 JVM 的堆,并且一旦所有数据都填满,我将忽略 XML 文件并继续对临时 SQLite 数据库进行操作。
还有其他方法可以解决我手头的问题吗?
【问题讨论】:
使用jaxb解析xml 正如其他人所说,您需要使用 SAX 解析器而不是 DOM 解析器,它将完全满足您的需求。阅读:***.com/questions/6828703/… 如果你不能保存整个 DOM 树,你必须找到一种方法来按顺序进行处理。那可能吗?你能展示一个 XSLT 来满足你的需要吗? 要解析大型 xml 文件,请始终使用 SAX Parser。参考以下链接*** 非顺序操作是什么意思?您的 XML 中是否有不同的数据,并且它们之间有交叉引用?无论您使用哪种 XML 解析器,都必须将所有数据存储在内存中。而是尝试向 JVM 提供更多-Xmx
,它应该可以轻松处理 1G。
【参考方案1】:
SAX (Simple API for XML) 会在这里为您提供帮助。
与 DOM 解析器不同,SAX 解析器不会在内存中创建 XML 文档的表示形式,因此速度更快,使用更少 记忆。相反,SAX 解析器通知客户端 XML 文档 通过调用回调来构建结构,也就是说,通过调用
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
【讨论】:
如果你做过SAX解析,你可能知道characters()
方法也很重要,你必须对字符数据做一个缓冲,因为它是不保证一个内容数据在一个块中处理(即可以立即完成两个character()
调用)。我认为值得一提。
我并不是说我的解决方案是完整的。这只是一个基本的实现。感谢您指出。我会更新我的答案。【参考方案2】:
如果您不想受内存限制的束缚,我当然建议您使用当前的方法,并将所有内容存储在数据库中。
XML 文件的解析应该由SAX parser
完成,正如每个人都建议的那样(包括我)。这样您可以一次创建一个对象,并且可以立即将其持久化到数据库中。
对于后处理(解决交叉引用),您可以使用数据库中的SELECT
s,制作主键、索引等。您也可以使用 ORM(Eclipselink、Hibernate)那个。
其实我不是很推荐SQLite,搭建一个mysql服务器比较容易,把数据存储在那里。以后您甚至可以重用 XML 数据(如果您不删除)。
【讨论】:
我想知道为什么有人会相信设置整个数据库服务器比使用嵌入式数据库更容易,在嵌入式数据库中您只需要包含一个 JAR 文件而无需安装任何东西。我认为对于这个用例,单独的数据库服务器将是矫枉过正。也许还有其他一些很好的理由使用数据库服务器,但更容易设置?真的吗? @vanje 我不是说 Oracle :) 我们在谈论 MySQL。说真的,我不敢相信任何开发人员设置 MySQL 服务器都会成为问题。 我认为每个开发人员都应该能够执行 Oracle 和 MySQL 的基本安装。我同意你的观点,Oracle 比 MySQL 复杂得多。但这不是重点。您将 MySQL 与 SQLite 进行了比较,并表示 MySQL 更易于设置。但是你没有提到你认为什么更容易。【参考方案3】:如果您想使用比 SAX 更高级别的方法(编程起来可能非常棘手),您可以使用最近的 Saxon-EE 版本查看流式 XSLT 转换。但是,您对正在执行的精确处理过于模糊,不知道这是否适用于您的特定情况。
【讨论】:
【参考方案4】:如果您需要一种资源友好的方法来处理非常大的 xml,请尝试以下操作: http://www.xml2java.net/xml-to-java-data-binding-for-big-data/ 它允许您以 SAX 方式处理数据,但具有获取高级事件(映射到 java 的 xml 数据)并能够直接在代码中使用这些对象的优势。因此它结合了 jaxb 的便利性和 SAX 资源友好性。
【讨论】:
以上是关于在 JAVA 中解析大型 XML 文档的主要内容,如果未能解决你的问题,请参考以下文章
如何停止在 Delphi 中使用 IVBSAXXMLReader 解析 XML 文档?