我是Java的新手,我希望对社区提出意见。 我有一个巨大的XML,其中包含很多信息。实际上,此XML具有大约140Mb的信息。 在此XML中,我有很多不再有效的信息,因此我需要进行过滤并仅使用有效的信息,要进行检查,我需要在节点之间交叉信息,以检查是否需要删除。在某些情况下,需要删除整个父(主)节点。
我已经使用dom解析,使用循环,在循环内部执行了此操作,我保存了变量并交叉了信息以进行检查,并删除了实际节点或整个父节点。
基本上,结构是这样的:
<source>
<main>
<id>98567</id>
<block_information>
<name>Block A</name>
<start_date>20120210</start_date>
<end_date>20150210</end_date>
</block_information>
<block_information>
<name>Block A.01</name>
<start_date>20150210</start_date>
<end_date>20251005</end_date>
</block_information>
<city_information>
<name>Manchester</name>
<start_date>20150210</start_date>
<end_date>20150212</end_date>
</city_information>
<city_information>
<name>New Manchester</name>
<start_date>20150212</start_date>
<end_date>20251005</end_date>
</city_information>
<phone>
<type>C</type>
<number>987466321</number>
<name></name>
</phone>
<phone>
<type>P</type>
<number>36547821</number>
<name></name>
</phone>
</main>
<main>
<id>19587</id>
<block_information>
<name>Che</name>
<start_date>20090210</start_date>
<end_date>20100210</end_date>
</block_information>
<block_information>
<name></name>
<start_date>20100210</start_date>
<end_date>20351005</end_date>
</block_information>
<city_information>
<name></name>
<start_date>20150210</start_date>
<end_date>20150212</end_date>
</city_information>
<city_information>
<name>No Name</name>
<start_date>20150212</start_date>
<end_date>20191005</end_date>
</city_information>
<phone>
<type>C</type>
<number>987466321</number>
<name>Mom</name>
</phone>
<phone>
<type>P</type>
<number>36547821</number>
<name></name>
</phone>
</main>
</source>
输出如下:
<result>
<main>
<id>98567</id>
<block_name>Block A.01</block_name>
<city_name>New Manchester</city_name>
<cellphone></cellphone>
<phone>36547821</phone>
<contact_phone></contact_phone>
<contact_phone_name></contact_phone_name>
</main>
</result>
要使结果有效,必须强制有一个<block_information>
和<city_information>
有效(<start_date>
比实际日期少,<end_date>
比实际日期大) ,并且两者都需要<name...>
。
如果没有任何一个或有效的多个,则<main>
将被删除。
对于电话号码,<type>
[“ C”代表联系人,“ P”代表个人电话,“ M”代表移动电话]。因此,如果<type>
为'C',但<name>
中没有值,则电话不会得到结果。 'P'转到<phone>
,'M'转到<cellphone>
。
我希望您考虑以最佳的方式执行此操作的最佳方法,如果需要的话,任何人都可以轻松地进行调整。
提前感谢您的投入!
按照@kjhughes的要求,我在示例XML上添加了一些值,并需要做一些过滤器。谢谢!
ps .:作为示例的XML结构与实际相比太简单了,有很多复杂的类型。
答案 0 :(得分:0)
我会采用以下方法:
Stream<Main>
Stream<Main>
并过滤每个Main
节点.parallel()
流来处理该流(请阅读:测试.parallel()
是否以任何方式对您有帮助)这将满足XML解析上下文中任何合理的性能要求(我想是吗?)。 Google for Java XML Stream
并从那里开始(或者也许this stackoverflow问题可以提供一些指导)
答案 1 :(得分:0)
XSLT是一种自1999年以来一直存在的转换语言,现在具有三个版本,即1.0、2.0和3.0,这是最新版本,于2017年作为W3C建议发布,并在Saxon 9.8和更高版本的Java平台上受支持,可在开放平台上获得:在Sourceforge和Maven上获得HE版本。通过合并Apache Xalan,Oracle / Sun Java JRE支持使用XSLT 1。
因此,可以选择使用XSLT来代替使用DOM,这是使用XSLT 3(在https://xsltfiddle.liberty-development.net/bFN1yab/0上在线)的示例:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output indent="yes"/>
<xsl:function name="mf:date" as="xs:date">
<xsl:param name="input-date" as="xs:string"/>
<xsl:sequence
select="xs:date(replace($input-date, '([0-9]{4})([0-9]{2})([0-9]{2})', '$1-$2-$3'))"/>
</xsl:function>
<xsl:function name="mf:select-valid-info" as="element()*">
<xsl:param name="infos" as="element()*"/>
<xsl:sequence
select="$infos[name/normalize-space()
and mf:date(start_date) lt current-date()
and mf:date(end_date) gt current-date()]"/>
</xsl:function>
<xsl:function name="mf:valid-main" as="xs:boolean">
<xsl:param name="main" as="element(main)"/>
<xsl:sequence
select="let $valid-blocks := mf:select-valid-info($main/block_information),
$valid-cities := mf:select-valid-info($main/city_information)
return count($valid-blocks) eq 1 and count($valid-cities) eq 1"/>
</xsl:function>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="main[not(mf:valid-main(.))]"/>
<xsl:template match="main[mf:valid-main(.)]">
<xsl:copy>
<xsl:apply-templates
select="id,
mf:select-valid-info(block_information)/name,
mf:select-valid-info(city_information)/name,
phone"/>
</xsl:copy>
</xsl:template>
<xsl:template match="block_information/name | city_information/name">
<xsl:element name="{substring-before(local-name(..), '_')}_name">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template match="main/phone[type = 'C']">
<contact_phone>
<xsl:value-of select="number[current()/normalize-space(name)]"/>
</contact_phone>
<contact_name>
<xsl:value-of select="name"/>
</contact_name>
</xsl:template>
<xsl:template match="main/phone[type = 'P']">
<phone>
<xsl:value-of select="number"/>
</phone>
</xsl:template>
<xsl:template match="main/phone[type = 'M']">
<cellphone>
<xsl:value-of select="number"/>
</cellphone>
</xsl:template>
</xsl:stylesheet>
我希望我已经掌握了main
元素的条件,虽然我还不太了解各种电话数据的规则,但是无论如何,该代码还是作为示例。
当然,性能很大程度上取决于实现,但是我认为XSLT是一种比DOM编码更加结构化和可维护的方式。
如果您负担得起的话,还可以研究支持流式XSLT 3的Saxon 9.8或9.9 EE,通过重写上面的代码,您可以使用基于XSLT的方法仅通过巨大的文档进行流式转发,具体实现{ {1}}元素是您要转换的元素节点,同时保持较低的内存占用,与DOM或常规XSLT处理相比,这种方法不会首先将整个XML文档解析为完整的内存树结构:
main