2015-11-30 151 views
3

我有一些XML看起來像下面這樣:刪除了過多的元素之間的多個XML元素

<FirstLevel> 
    <item1>Val1</item1> 
    <item2>Val2</item2> 
    <item3>Val3</item3> 
    <item4>Val4</item4> 
    <item5>Val5</item5> 
</FirstLevel> 

使用Python,我想刪除item1item5之間的所有項目,而不必明確的名字,得到結果如下:

<FirstLevel> 
    <item1>Val1</item1> 
    <item5>Val5</item5> 
</FirstLevel> 

隨着lxml,我知道如何找到item1item5,所以我只需要知道如何建立某種形式的XML元素的列表它們是T之間這兩個。

+0

在Python中,讀取文件通常要容易得多,刪除所需的部分然後重寫文件。它可能與您使用的模塊idk不同。 –

+0

感謝您的快速回答。在我的情況下,訪問該文件很困難,因爲它在更大的用例中存在,但是如果我找不到其他解決方案,我會考慮它:) – filaton

回答

1

感謝alecxe,我找到了解決方案。如果我們有多個item1-item5元素的實例(請參閱我對他的答案的評論以便更好地理解),他的回答對於所描述的案例完全適用,但不起作用(即使是他的更新)。

無論如何,我發現了另一種解決方案(我認爲這是更簡單,更符合Python):

from lxml.etree import fromstring, tostring 

data = """<FirstLevel> 
    <item1>Val1</item1> 
    <item2>Val2</item2> 
    <item3>Val3</item3> 
    <item4>Val4</item4> 
    <item5>Val5</item5> 
    <item1>Val1</item1> 
    <item2>Val2</item2> 
    <item3>Val3</item3> 
    <item4>Val4</item4> 
    <item5>Val5</item5> 
</FirstLevel> 
""" 

tree = fromstring(data) 

item1_list = tree.findall("item1") 

for item1 in item1_list: 
    next_node = item1.getnext() 
    while next_node.tag != "item5": 
     tree.remove(next_node) 
     next_node = item1.getnext() 

print(tostring(tree)) 

還有一個從alecxe評論這對我的作品來了一個解決方案:

從lxml.etree import fromstring,tostring

data = """<FirstLevel> 
    <item1>Val1</item1> 
    <item2>Val2</item2> 
    <item3>Val3</item3> 
    <item4>Val4</item4> 
    <item5>Val5</item5> 
    <item1>Val1</item1> 
    <item2>Val2</item2> 
    <item3>Val3</item3> 
    <item4>Val4</item4> 
    <item5>Val5</item5> 
    <item1>Val1</item1> 
    <item2>Val2</item2> 
    <item3>Val3</item3> 
    <item4>Val4</item4> 
    <item5>Val5</item5> 
</FirstLevel> 
""" 

tree = fromstring(data) 
node_start = "item1" 
node_end = "item5" 

parent = tree.xpath("//FirstLevel")[0] 
# Remove first section 
for node in parent.xpath("*[(preceding-sibling::item1)[1] and (following-sibling::item5)[3]]"): 
    parent.remove(node) 
# Remove second section 
for node in parent.xpath("*[(preceding-sibling::item1)[2] and (following-sibling::item5)[2]]"): 
    parent.remove(node) 
# Remove last section 
for node in parent.xpath("*[(preceding-sibling::item1)[3] and (following-sibling::item5)[last()]]"): 
    parent.remove(node) 

print(tostring(tree)) 

我找到了正確的索引來把我n preceding-following-sibling通過嘗試多個值,但仍然沒有真正得到它的邏輯,但它至少對我有效。

3

您可以使用preceding-siblingfollowing-sibling,例如組合:

from lxml.etree import fromstring, tostring 

data = """<FirstLevel> 
    <item1>Val1</item1> 
    <item2>Val2</item2> 
    <item3>Val3</item3> 
    <item4>Val4</item4> 
    <item5>Val5</item5> 
</FirstLevel> 
""" 

tree = fromstring(data) 
node_start = "item1" 
node_end = "item5" 

parent = tree.xpath("//FirstLevel")[0] 
for node in parent.xpath("*[preceding-sibling::%s and following-sibling::%s]" % (node_start, node_end)): 
    parent.remove(node) 

print(tostring(tree)) 

打印:

<FirstLevel> 
    <item1>Val1</item1> 
    <item5>Val5</item5> 
</FirstLevel> 

如果能有item1item5單節點內多次出現:

item_start = "item1" 
item_end = "item5" 

parent = tree.xpath("//FirstLevel")[0] 
for node_start in parent.xpath("%s" % item_start): 
    for node in node_start.xpath("following-sibling::%s" % item_end): 
     parent.remove(node) 
+0

非常感謝您的答案,描述。 但是,如果我們考慮重複兩次我們的「itemN」元素(使item1到item5再到item1再次到item5)的情況,它將刪除第一個item1和最後一個item5之間的所有元素。我怎麼能再次獲取item1,item5,item1和item5。我希望這是明確:) – filaton

+0

@filaton我想我明白你的意思。請參閱更新。謝謝。 – alecxe