用Java分割大型XML文件

上周,我被要求用Java编写一些东西,该东西能够将单个30GB XML文件拆分为可配置文件大小的较小部分。 该文件的使用者将是一个中间件应用程序,该应用程序存在XML较大的问题。 在后台,它使用某种DOM解析技术,使它在一段时间后耗尽内存。 由于它是基于供应商的中间件,因此我们无法自行纠正。 最好的选择是创建一些预处理工具,该工具会先将大文件分成多个较小的块,然后再由中间件处理。

XML文件带有一个相应的W3C模式,该模式由强制性头部分和紧随其后嵌套有多个0 .. *数据元素的内容元素组成。 对于演示代码,我以简化形式重新创建了架构:
图式 模式(1) 标头的大小可以忽略。 单个数据元素的重复也很小,可以说少于50kB。 由于数据元素重复的次数,XML太大了。 要求是:

  • 分割后的XML的每一部分都应为语法有效的XML,并且每一部分还应针对原始模式进行验证
  • 该工具应根据架构验证XML,并报告所有验证错误。 验证不得阻塞,并且不可在输出中跳过非验证元素或属性
  • 对于标头,决定将其复制到每个新的输出文件中,而不是将其复制到每个新的输出文件中,并使用一些处理信息和一些默认值来重新生成该标头

因此,使用诸如Unix Split之类的二进制拆分工具是不可能的。 在固定数量的字节之后,这将拆分,从而确保XML损坏。 我不太确定,但是诸如Split之类的工具也不了解编码。 因此,在字节“ x”之后进行拆分不仅会导致在XML元素的中间进行拆分(例如),而且甚至会在字符编码序列的中间进行拆分(例如,在使用经过UTF8编码的Unicode时)。 显然,我们需要更智能的东西。

XSLT作为核心技术也是行不通的。 乍一看,可能会很想尝试:使用XSLT2.0,可以从单个输入文件创建多个输出文件。 甚至可以在转换时验证输入文件。 但是,细节始终是魔鬼。 否则,在Java中进行简单的操作(例如将验证错误写入单独的文件或检查当前输出文件的大小)可能需要自定义Java代码。 对于Xalan和Saxon来说,当然可以有这样的扩展,但是Xalan不是XSLT2.0实现,因此只剩下Saxon。 最后但并非最不重要的一点是,XSLT1.0 / 2.0是非流式的,这意味着它们会将整个源文档读入内存,因此这显然将XSLT排除在了可能性之外。

剩下的唯一选择就是Java XML解析。 当然,在这种情况下,理想的选择是StAX。 我不在这里进行SAX与StAX的比较,事实是StAX能够针对架构的身份进行验证(至少某些解析器可以)并且还可以编写XML。 而且,与SAX相比,API的使用要容易得多,因为基于pull的API提供了对迭代文档的更多控制,并且比SAX的推送方式更令人愉快。 好的,我们需要什么:

  • 能够验证XML的StAX实现
    • Oracle的JDK默认附带SJSXP作为StAX实现,但是此验证无效。
  • 最好具有某种对象/ XML映射技术,用于(重新)创建标头,而不是手动摆弄元素并必须查找正确的数据类型/格式
    • 显然是JAXB。

该代码有点大,无法在此处整体显示。 可以访问源文件,XSD和测试XML
了这里 GitHub上。 它具有Maven pom文件,因此您应该能够在选择的IDE中将其导入。 JAXB绑定编译器将自动编译模式,并将生成的源放在类路径上。

public void startSplitting() throws Exception {
  XMLStreamReader2 xmlStreamReader = ((XMLInputFactory2) XMLInputFactory.newInstance())
    .createXMLStreamReader(BigXmlTest.class.getResource("/BigXmlTest.xml"));
  PrintWriter validationResults = enableValidationHandling(xmlStreamReader);

  int fileNumber = 0;
  int dataRepetitions = 0;
  XMLStreamWriter xmlStreamWriter = openOutputFileAndWri
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值