簡體   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