繁体   English   中英

如何合并两个lxml.objectify元素?

[英]How do I merge two lxml.objectify elements?

我正在解析一些XML配置以使用其中的设置。 我不会再写出XML,因此我的兴趣只是提取。

我有两个lxml.objectify元素:一方面是一个包含默认全局设置的元素,另一方面是一个包含特定于实例的设置。 每个元素的结构都类似(例如,root.global_settings.lights与root.instance_settings.lights具有相同的设置),但是可能存在交集和设置差异。 元素包含一些子文本节点,但也包含包含其他节点的节点。

我想要的是:包含两个元素的所有设置的单个元素。 特定于实例的设置将覆盖全局设置。

我目前最好的解决方案是遍历实例子对象并覆盖/添加到全局子对象(在有文本节点的所有级别)。 我在想也许会有更多类似dict.update的东西吗?

编辑:仅举一个例子

<global>
    <birthday>Unknown</birthday>
    <wishes>
        <cake>Chocolate</cake>
        <gift>Book</gift>
    </wishes>
</global>

<instance>
    <name>Mike</name>
    <birthday>06-06-1974</birthday>
    <wishes>
        <notes>Hates flowers</notes>
    </wishes>
<instance>

会产生与我在上面运行objectify.parse相同的结果

<global>
    <name>Mike</name>
    <birthday>06-06-1974</birthday>
    <wishes>
        <cake>Chocolate</cake>
        <gift>Book</gift>
        <notes>Hates flowers</notes>
    </wishes>
</global>

我没有找到任何“本地” lxml解决方案。 Objectify元素具有两个字典(您可以像字典一样访问它们的值)和列表(可以将一个元素与其他元素一起扩展和追加)的特征。 但是,更新根本不起作用,并且扩展具有严格的限制,包括缺乏递归性。

因此,我将这个递归函数放在一起,该递归函数使用另一个元素来更新一个元素。 此处的特定上下文是使用用户设置覆盖默认设置,而在没有用户设置的情况下保留默认设置。

本质上,该函数区分由两个特征定义的四种节点:

1)默认设置中是否缺少该节点? 如果是这样,我们可以复制(追加)用户一个。

2)如果节点默认设置也发现,我们需要作出进一步的区分:它是一个DataElement -即一个节点具有直接的数据值,例如<name>Mike</name> -或更多的“没有直接数据值的结构化节点,例如上例中的<wishes>...</wishes> 在第一种情况下,我们用用户一个替换默认节点(和值)。 在第二个步骤中,我们需要更深一层,并重复整个过程。

def merge(user_el, default_el):
    '''Updating one lxml objectify elements with another'''
    for child in user_el.iterchildren():
        default_child = default_el.find(child.tag)
        if default_child is None:
            default_el.append(child)
            continue
        if isinstance(child, objectify.ObjectifiedDataElement):
            default_el.replace(default_child, child)
        elif isinstance(child, objectify.ObjectifiedElement):
            merge(child, default_child)

编辑:测试以上内容使我意识到,如果默认情况下还存在的结构用户元素(例如,空节点)具有多个具有相同标签名称的子节点,它们将逐渐替换彼此的数据子节点。 为避免这种情况,我创建了一个可编辑默认设置副本的版本。 这样,我们将继续检查空的占位符元素,而不是逐步填充的元素。

new_xml = copy.deepcopy(DEFAULT_XML)
merge(user_xml, new_xml, DEFAULT_XML)

def merge(user_el, new_el, default_el):
   '''Updating one lxml objectify elements with another'''
   for child in user_el.iterchildren():
       new_child = new_el.find(child.tag)
       default_child = default_el.find(child.tag)
       if default_child is None:
           new_el.append(child)
           continue
       if isinstance(child, objectify.ObjectifiedDataElement):
           new_el.replace(new_child, child)
       elif isinstance(child, objectify.ObjectifiedElement):
           merge(child, new_child, default_child)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM