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