【问题标题】:Splitting large xml files in n groups将大型 xml 文件拆分为 n 个组
【发布时间】:2018-06-22 23:49:48
【问题描述】:

我有一个大型 xml 文件,其父标签有 97k 个子标签。我想分成 10 个文件,每个文件有 10k 个标签,最后一个带有剩余的标签。

我有这段代码用于向每个文件写入一个子标签,但无法提出组。

假设我的示例 xml 有 10 个子标签,我想创建 5 个文件,每个文件有 2 个子标签。

我的示例 xml:

<root>
    <row>
        <NAME>A</NAME>
        <FIRSTNAME>A</FIRSTNAME>
        <GENDER>M</GENDER>
    </row>
    <row>
        <NAME>B</NAME>
        <FIRSTNAME>B</FIRSTNAME>
        <GENDER>M</GENDER>
    </row>
<row>
        <NAME>A</NAME>
        <FIRSTNAME>A</FIRSTNAME>
        <GENDER>M</GENDER>
    </row>
    <row>
        <NAME>B</NAME>
        <FIRSTNAME>B</FIRSTNAME>
        <GENDER>M</GENDER>
    </row>
<row>
        <NAME>A</NAME>
        <FIRSTNAME>A</FIRSTNAME>
        <GENDER>M</GENDER>
    </row>
    <row>
        <NAME>B</NAME>
        <FIRSTNAME>B</FIRSTNAME>
        <GENDER>M</GENDER>
    </row>
<row>
        <NAME>A</NAME>
        <FIRSTNAME>A</FIRSTNAME>
        <GENDER>M</GENDER>
    </row>
    <row>
        <NAME>B</NAME>
        <FIRSTNAME>B</FIRSTNAME>
        <GENDER>M</GENDER>
    </row>
<row>
        <NAME>A</NAME>
        <FIRSTNAME>A</FIRSTNAME>
        <GENDER>M</GENDER>
    </row>
    <row>
        <NAME>B</NAME>
        <FIRSTNAME>B</FIRSTNAME>
        <GENDER>M</GENDER>
    </row>
</root>

我的结果应该是 5 个文件,每个文件有 2 个条目,如下所示:

<root>
        <row>
            <NAME>A</NAME>
            <FIRSTNAME>A</FIRSTNAME>
            <GENDER>M</GENDER>
        </row>
        <row>
            <NAME>B</NAME>
            <FIRSTNAME>B</FIRSTNAME>
            <GENDER>M</GENDER>
        </row>
</root>

下面的代码为每个文件放置了每个子标签,但我希望在这里例如每个文件有 2 个标签。

import xml.etree.ElementTree as ET
context = ET.iterparse('file.xml', events=('end', ))
index = 0
for event, elem in context:
    if elem.tag == 'row':
        index += 1
        filename = format(str(index) + ".xml")
        with open(filename, 'wb') as f:
            f.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
            f.write(ET.tostring(elem))

提前致谢!

编辑以添加食谱:

from itertools import zip_longest

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

【问题讨论】:

    标签: python xml-parsing elementtree


    【解决方案1】:

    你有一个可迭代的(事件、元素)对:

    context = ET.iterparse('file.xml', events=('end', ))
    

    现在,您想将其过滤到仅row 元素:

    rows = (elem for event, elem in context if elem.tag == 'row')
    

    现在您想对它们进行分组。使用the grouper recipe from the itertools docs

    groups = grouper(rows, 2)
    

    您显然可以将 2 更改为 1000 或其他任何东西,一旦您开始工作并想要真正运行它。

    现在,您可以迭代组。当我们这样做的时候,让我们使用enumerate 这样你就不需要手册index += 1 的东西了。另外,与其手动构建一个字符串然后在其上毫无意义地调用format,不如直接使用an f-string

    for index, group in enumerate(groups):
        # If you need to run on 3.5 or 2.7, use "{}.xml".format(index)
        filename = f"{index}.xml"
        with open(filename, 'wb') as f:
            f.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
    

    …然后迭代组内的元素——但要小心;如果您有奇数个元素,grouper 将使用 None 值填充不完整的最后一组。1

            for elem in group:
                if elem:
                    f.write(ET.tostring(elem))
    

    1。这并不难改变,但我直接使用文档中的配方,所以我不必解释如何改变它。

    【讨论】:

    • @abarnet 感谢您的回复。石斑鱼需要什么确切的进口声明? import itertools 或 from itertools import groupby 不起作用。
    • @Atihska 这是文档中的食谱。您不能从文档中的食谱中导入代码;您必须将其键入或复制并粘贴到您的代码中。他们这样做是因为 (a) 它只有两行,并且 (b) 这是他们希望您阅读的有用示例代码。但是,如果您真的想这样做,第三方库中也有等效的函数,例如 more_itertoolstoolz。 (另外,你为什么期望from itertools import groupby 给你一个名为grouper 的函数?)
    • 哦,我是python新手,不知道菜谱。需要复制什么代码?
    • 我添加了代码。请检查我的编辑,但这也不起作用。
    • 知道了。我正在使用 python2,名称是 izip_longest
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-21
    • 2021-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    相关资源
    最近更新 更多