[英]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.