删除 too 元素之间的多个 XML 元素
Deleting multiple XML elements between too elements
我有一些 XML 如下所示:
<FirstLevel>
<item1>Val1</item1>
<item2>Val2</item2>
<item3>Val3</item3>
<item4>Val4</item4>
<item5>Val5</item5>
</FirstLevel>
使用 Python,我想删除 item1
和 item5
之间的所有项目,而不必明确命名,以获得以下结果:
<FirstLevel>
<item1>Val1</item1>
<item5>Val5</item5>
</FirstLevel>
有了 lxml
,我知道如何找到 item1
和 item5
,所以我只需要知道如何构建某种 XML 元素的列表,这些元素是在这两者之间。
您可以使用 preceding-sibling
and following-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>
如果您可以在单个节点内多次出现 item1
和 item5
:
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)
感谢 alecxe,我找到了解决方案。如果我们有多个 item1-item5 元素实例(请参阅我对他的回答的评论以更好地理解),他的回答非常适合所描述的案例但不起作用(即使有他的更新)。
无论如何,我找到了另一个解决方案(我认为它更简单,更符合 Pythonic):
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 评论的解决方案对我有用:
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>
<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))
我通过尝试多个值找到了放入 preceding-
和 following-sibling
的正确索引,但仍然没有真正理解其背后的逻辑,但它至少对我有用。
我有一些 XML 如下所示:
<FirstLevel>
<item1>Val1</item1>
<item2>Val2</item2>
<item3>Val3</item3>
<item4>Val4</item4>
<item5>Val5</item5>
</FirstLevel>
使用 Python,我想删除 item1
和 item5
之间的所有项目,而不必明确命名,以获得以下结果:
<FirstLevel>
<item1>Val1</item1>
<item5>Val5</item5>
</FirstLevel>
有了 lxml
,我知道如何找到 item1
和 item5
,所以我只需要知道如何构建某种 XML 元素的列表,这些元素是在这两者之间。
您可以使用 preceding-sibling
and following-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>
如果您可以在单个节点内多次出现 item1
和 item5
:
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)
感谢 alecxe,我找到了解决方案。如果我们有多个 item1-item5 元素实例(请参阅我对他的回答的评论以更好地理解),他的回答非常适合所描述的案例但不起作用(即使有他的更新)。
无论如何,我找到了另一个解决方案(我认为它更简单,更符合 Pythonic):
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 评论的解决方案对我有用:
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>
<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))
我通过尝试多个值找到了放入 preceding-
和 following-sibling
的正确索引,但仍然没有真正理解其背后的逻辑,但它至少对我有用。