处理大型 xml 文件。只有根树的子属性是相关的

Processing large xml files. Only root tree children attributes are relevant

我是 xml 和 python 的新手,我希望我的问题表述正确:

我有 xml 个大小为 1 GB 的文件。 文件如下所示:

<test name="LongTestname" result="PASS">
    <step ID="0" step="NameOfStep1" result="PASS">
        Stuff I dont't care about
    </step>
    <step ID="1" step="NameOfStep2" result="PASS">
        Stuff I dont't care about
    </step>
</test>

为了快速分析,我想获取作为根元素子元素的步骤的名称和结果。我不关心的是很多嵌套元素。

我已经尝试过以下操作:

tree = ET.parse(xmlLocation)
root = tree.getroot()
for child in root:
    print(child.tag, child.attrib)

这里我遇到了内存错误,因为文件太大了

然后我尝试了:

try:
    for event, elem in ET.iterparse(pathToSteps, events=("start","end")):
       if elem.tag == "step" and event == "start":
                        
           stepAndResult.append([elem.attrib['step'],elem.attrib['result'],"System1"])
       elem.clear()

这有效,但速度很慢。我想它会遍历所有元素,这需要很长时间。

然后我找到了一个看起来像这样的解决方案:

try:
    tree = ET.iterparse(pathToSteps, events=("start","end"))
    _, root = next(tree)  
    print('ROOT:', root.tag)
except:
   print("ERROR: Unable to open and parse file !!!")


for child in root:
   print(child.attrib)

但这只打印第一步的属性。

有没有办法加快解决方案的速度? 由于我对这些东西很陌生,我希望能有一个完整的例子或参考,我可以通过一个例子自己弄明白。

在不知道您的设置细节的情况下,可能很难猜测 'fastest possible' 可能是什么以及有多少延迟是由于文件解析造成的。我要做的第一件事当然是给 运行 计时,这样您就有了一些初始基准。然后我会写一个简单的 python 程序,除了从磁盘读取文件(没有 XML 解析)之外什么都不做。如果时间差异不大,那么 XML 解析不是问题,问题是从磁盘读取文件。当然,在 XML 文档中,文件本身没有指示下一个标记结束的位置,因此不可能跳过与这些部分关联的 IO(您仍然需要对文件进行线性读取) .除了可能使用不同的编程语言(非解释型)之外,您可以做的事情可能并不多。

如果在实际的 XML 解析中确实出现明显的速度下降,您可能会尝试将文件预处理为另一个文件。由于文件的文件格式非常静态,您可以读取文件并输出到不同的文件(使用正则表达式),直到获得标签。然后丢弃数据,直到关闭 </step> 标签或 </test> 标签。这将生成一个有效但希望小得多的 XML 文件。这里的关键是自己做 'parsing' 而不是让底层解析器尝试理解所有文档格式,这可能会更快,因为您的格式很简单。然后,您可以 运行 在此输出上的原始程序不会 'see' 任何无关的标签。当然,如果你真的有嵌套的 <step> 标签,这会中断,但如果是这种情况,那么你可能需要用真正的 XML 解析器解析文件以了解第一级开始的位置和停止。

我认为您 iterparse() 的方向是正确的。

也许可以尝试在 tag 参数中指定 step 元素名称并只处理“开始”事件...

from lxml import etree

for event, elem in etree.iterparse("input.xml", tag="step", events=("start",)):
    print(elem.attrib)
    elem.clear()

编辑: 出于某种原因,我认为您使用的是 lxml 而不是 ElementTree。我的回答会要求您切换到 lxml。