【问题标题】:Set the value of XML file recursively with Python ElementTree?使用 Python ElementTree 递归设置 XML 文件的值?
【发布时间】:2011-01-24 23:54:45
【问题描述】:

我得到了一个如下的 XML 文件。

<?xml version="1.0" encoding="UTF-8"?>
<A value="?">
    <B value="?">
        <C value="10"/>
        <C value ="20"/>
    </B>
    <B value="?">
        <C value = "5" />
        <C value = "10" />
    </B>
</A>

如何对子节点的值求和以递归设置父节点?

<?xml version="1.0" encoding="UTF-8"?>
<A value="45">
    <B value="30">
        <C value="10"/>
        <C value ="20"/>
    </B>
    <B value="15">
        <C value = "5" />
        <C value = "10" />
    </B>
</A>

【问题讨论】:

    标签: python xml elementtree


    【解决方案1】:

    以下代码在 Python 3.1.3(已显示)和 Python 2.7.1(未显示)中未更改。完成所有工作的功能与版本无关。您可能想要更改其他有趣的位(从文件而不是字符串解析,导入其他一些 ElementTree 实现等)以适合自己。

       >>> xml_in = """
        ... <A value="?">
        ...     <B value="?">
        ...         <C value="10"/>
        ...         <C value ="20"/>
        ...     </B>
        ...     <B value="?">
        ...         <C value = "5" />
        ...         <C value = "10" />
        ...     </B>
        ... </A>
        ... """
        >>> import xml.etree.ElementTree as et
        >>> def updated_value(elem):
        ...     value = elem.get('value')
        ...     if value != '?': return int(value)
        ...     total = sum(updated_value(child) for child in elem)
        ...     elem.set('value', str(total))
        ...     return total
        ...
        >>> root = et.fromstring(xml_in)
        >>> print("grand total is", updated_value(root))
        grand total is 45
        >>> import sys; nbytes = sys.stdout.write(et.tostring(root) + '\n')
        <A value="45">
            <B value="30">
                <C value="10" />
                <C value="20" />
            </B>
            <B value="15">
                <C value="5" />
                <C value="10" />
            </B>
        </A>
        >>>
    

    【讨论】:

    • 如果元素没有value 属性,那么updated_value() 将不起作用,因为int(None) 引发TypeError
    • @J.F. Sebastian:如果他的样本数据与现实世界不同,我有点希望 OP 能够做出必要的调整。事实上,如果一个元素没有 value 属性或者它包含“?”以外的内容,它“将不起作用”。或一个 int-worthy 字符串。 OP 没有说明在这种意外情况下要采取什么行动;每种情况的可能性包括 (1) 异常 (2) 立即返回 0 (3) 继续到 sum(children) 阶段(这将“修复”有问题的元素)。
    【解决方案2】:

    如果您特别需要递归解决方案,那么@John Machin's answer 很好。但是你可以迭代地做:

    from xml.etree import cElementTree as etree # adjust it for your python version
    
    for ev, el in etree.iterparse('you_file.xml'):
        if el.get('value') == '?':
           el.set('value', str(sum(int(n.get('value')) for n in el)))
    
    print(etree.tostring(el))
    

    输出

    <A value="45">
        <B value="30">
            <C value="10" />
            <C value="20" />
        </B>
        <B value="15">
            <C value="5" />
            <C value="10" />
        </B>
    </A>
    

    【讨论】:

    • 您的答案“也不起作用”:如果 n.get('value') 返回的不是 int-worthy 字符串,则会引发异常。如果非叶子元素没有value 属性,它将静默失败。
    • @John Machin:我的回答只对具有 'value="?"' 属性的元素的直接子元素求和。如果value 不是int-worthy,它应该会失败。这与在您的情况下要求 all 元素具有有效的 value 属性不同。无论如何,这个问题闻起来像家庭作业,所以我们在这里讨论什么目的?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-02
    • 2019-03-23
    • 2015-11-04
    • 2014-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多