我正在尝试使用此 XSLT 样式表将 13GB 的 xml 文件拆分为约 50MB 的小 xml 文件。
但是当我发现 xsltproc 占用了超过 1.7GB 的内存(这是系统的总内存量)后,该进程就终止了。
有没有办法用 xsltproc 处理巨大的 XML 文件?我可以更改样式表吗?还是我应该使用其他处理器?还是我只是 SOL?
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl"
xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="block-size" select="75000"/>
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates select="mysqldump/database/table_data/row[position() mod $block-size = 1]" />
</xsl:copy>
</xsl:template>
<xsl:template match="row">
<exsl:document href="chunk-{position()}.xml">
<add>
<xsl:for-each select=". | following-sibling::row[position() < $block-size]" >
<doc>
<xsl:for-each select="field">
<field>
<xsl:attribute name="name"><xsl:value-of select="./@name"/></xsl:attribute>
<xsl:value-of select="."/>
</field>
<xsl:text>
</xsl:text>
</xsl:for-each>
</doc>
</xsl:for-each>
</add>
</exsl:document>
</xsl:template>
答案1
这个简单的实用程序要求您有 Python 和 python-lxml 模块(系统中安装了 libxml2),它将允许您流式解析元素,通过 XSLT 转换每个元素并立即将其写入结果文件,无需缓冲
#!/usr/bin/env python3
from lxml import etree
import re
_xslt = etree.parse('FILL_XSLT_DOC')
_dom = etree.iterparse('FILL_SOURCE_XML')
transform = etree.XSLT(_xslt)
results = open('FILL_RESULT_XML','w+b')
for elem in _dom:
if (elem[1].tag.endswith('FILL_SEARCHED_ELEMENT_NAME')):
newElem = transform(elem[1])
#print(etree.tostring(newElem,xml_declaration = False,encoding='utf8'))
results.write(etree.tostring(newElem,xml_declaration = False,encoding='utf8'))
results.write(b'\n')
好的,请注意,如果您的 XSLT 包含<xsl:strip-space elements="*"/>
此 2010 年错误,您可能会受到影响,https://bugs.launchpad.net/lxml/+bug/583249
答案2
嗯,似乎有一个流式 XML 选项,它与 XSLT 有点不同(xslt 要求整个文档放入内存,而流式 xml 转换语言则不需要)。
我没有重写刚刚花了一天时间准备的 XSLT,而是启动了一个具有 64 GB RAM 的 AWS 现货实例,给它一些交换,而我的 13GB XML 在 xsltproc 下消耗了大约 65GB 的 RAM。
它可以在此系统上运行,但我现在可以告诉你,即使是亚马逊最大的高内存实例,你也无法从中获得超过 13GB 的文件。你需要采用另一种解决方案,例如流式 XML 转换。
作为任何想要突破极限的人的基准。此转换在具有 32 GB RAM 和 120G 交换分区的实例上失败。似乎您可以交换几 GB,但不要交换太多,否则会遇到一些会导致其崩溃的问题。