遍历一个大型XML文件

7

我遇到了一个问题,需要循环处理一个大约20-30MB(650000行)的XML文件。

这是我的伪代码:

<cffile action="READ" ile="file.xml" variable="usersRaw">

<cfset usersXML = XmlParse(usersRaw)>
<cfset advsXML = XmlSearch(usersXML, "/advs/advuser")>
<cfset users = XmlSearch(usersXML, "/advs/advuser/user")>

<cfset numUsers = ArrayLen(users)>
<cfloop index="i" from="1" to="#numUsers#">
    ... some selects...
    ... insert...
    <cfset advs = annunciXml[i]["vehicle"]>
    <cfset numAdvs = ArrayLen(advs)> 
    <cfloop index="k" from="1" to="#numAdvs#">        
        ... insert... or ... update...
    </cfloop>
</cfloop>

XML文件的结构如下(是的,不太好看):
<advs>
   <advuser>
      <user>
      </user>
      <vehicle>
      <vehicle>
   </advuser>
</advs>

在大约12万行后,我会收到一个错误:“内存不足”。

我该如何提高脚本的性能?

我该如何诊断最大内存消耗的位置?

4个回答

11

@SamG正确指出ColdFusion XML解析器无法实现此功能,因为使用DOM解析器是不可行的,但SAX很麻烦。相反,请使用StAX解析器,它提供了一个更简单的迭代器接口。请查看我回答另一个问题的示例,了解如何在ColdFusion中实现这一点。

以下是您在示例中要执行的大致操作:

<cfset fis = createObject("java", "java.io.FileInputStream").init(
    "#getDirectoryFromPath(getCurrentTemplatePath())#/file.xml"
)>
<cfset bis = createObject("java", "java.io.BufferedInputStream").init(fis)>
<cfset XMLInputFactory = createObject("java", "javax.xml.stream.XMLInputFactory").newInstance()>
<cfset reader = XMLInputFactory.createXMLStreamReader(bis)>

<cfloop condition="#reader.hasNext()#">
    <cfset event = reader.next()>
    <cfif event EQ reader.START_ELEMENT>
        <cfswitch expression="#reader.getLocalName()#">
            <cfcase value="advs">
                <!--- root node, do nothing --->
            </cfcase>
            <cfcase value="advuser">
                <!--- set values used later on for inserts, selects, updates --->
            </cfcase>
            <cfcase value="user">
                <!--- some selects and insert --->
            </cfcase>
            <cfcase value="vehicle">
                <!--- insert or update --->
            </cfcase>
        </cfswitch>
    </cfif>
</cfloop>

<cfset reader.close()>

ColdFusion是一个与JavaScript兼容的环境吗? - vtd-xml-author
@vtd-xml-author:请解释一下您所说的“兼容环境”的含义。ColdFusion的主要目的是作为服务器端语言来响应HTTP请求。因此,它的输出通常是HTML、CSS和JavaScript。而且,它还具有轻松响应AJAX请求的功能。 - orangepips
只是出于好奇,如果您使用jQuery解析XML,然后将结果发送到ColdFusion CFC,那么谁会逐行处理数据。这只是一个想法。 - crosenblum
3
我虽然没有尝试过,但相信JavaScript(以及扩展的jQuery)也会创建一个DOM表示,因此这可能也会受到内存限制的影响。 - orangepips

2
orangepips提供了一个合理的解决方案。请参考Ben Nadel在ColdFusion中处理非常大的XML文件的解决方案。我已经在一个大小为50MB,拥有120万行的XML文件上测试过他的方法。Ben使用了与orangepips类似的方法--使用Java流式传输,然后在ColdFusion中XMLParse每个节点以获取所需内容。看看它--像Ben Nadel的大多数代码和教程一样,它非常好用。 http://www.bennadel.com/blog/1345-Ask-Ben-Parsing-Very-Large-XML-Documents-In-ColdFusion.htm

1

我相信 Cold Fusion XML 解析器采用的是 DOM 解析,对于这种文件大小并不适合。你应该尝试找到一个 SAX 解析器,这些解析器都是事件驱动的。也许这个链接能够帮到你 http://coldfusion.sys-con.com/node/236002


1

我不懂ColdFusion,但20-30Mb并不超出构建内存树的技术范围;许多人经常对200Mb文件运行XSLT转换。

转向SAX解析听起来像是一种极端措施 - 这是一个非常底层的接口。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接