У меня есть xml файл:
<?xml version="1.0" encoding="UTF-8"?>
<kw name="k1" library="k1">
<kw name="k2" library="k2">
<kw name="Keep This" library="Keep This">
<c name="c4" library="c4">
</c>
</kw>
<kw name="k3" library="k3">
<c name="c4" library="c4">
</c>
</kw>
<c name="c3" library="c3">
<c name="c4" library="c4">
</c>
</c>
</kw>
</kw>
И я хочу удалить таблицу, но за исключением выполнения следующего правила:
Другая таблица должна быть удалена из xml
Таким образом, вывод должен выглядеть следующим образом:
<?xml version="1.0" encoding="UTF-8"?>
<kw name="k1" library="k1">
<kw name="k2" library="k2">
<kw name="Keep This" library="Keep This">
<c name="c4" library="c4">
</c>
</kw>
<c name="c3" library="c3">
<c name="c4" library="c4">
</c>
</c>
</kw>
</kw>
Очень сложно отслеживать рекурсивную функцию, может ли кто-нибудь помочь мне или порекомендовать другой способ для выполнения моих требований?
import xml.etree.ElementTree as ET
tree = ET.parse('a.xml')
root = tree.getroot()
def check(root):
# if subchild exist "kw" tag, parse to the subchild
if 'kw' in ([child.tag for child in root]):
for child in root:
flag = check(child)
# remove
if not flag:
root.remove(child)
# if subchild dose not exist "kw" tag
else:
if root.tag == 'kw':
# Check if itself tag is kw and "Keep this"
if 'Keep This' in [root.attrib[child] for child in root.attrib]:
return True
# Remove if itself tag is kw but without "Keep this"
else:
print ('remove')
return False
else:
return True
check(root)
ET.dump(root)
Вместо этого вы можете использовать следующую рекурсивную функцию. Обратите внимание на использование исключения в качестве способа уведомить родителя об удалении дочернего элемента, поскольку удаление узла должно выполняться из родителя, а возвращаемое значение Boolean указывает только, является ли потомком с тегом kw
и значением атрибута Keep This
найдено. Это имеет смысл уведомлять вызывающего абонента, когда в корневом узле отсутствует узел "держать", который, согласно правилу, должен быть удален, но не может быть потому, что он является корневым узлом:
import xml.etree.ElementTree as ET
def check(node):
if node.tag == 'kw' and any(value == 'Keep This' for value in node.attrib.values()):
return True
keep = False
removals = []
for child in node:
try:
if check(child):
keep = True
except RuntimeError:
removals.append(child)
for child in removals:
node.remove(child)
if node.tag == 'kw' and not keep:
raise RuntimeError('No "keep" node found under this node')
return keep
tree = ET.parse('a.xml')
root = tree.getroot()
check(root)
ET.dump(root)
С помощью вашего ввода сэмпла эти выходы:
<kw library="k1" name="k1">
<kw library="k2" name="k2">
<kw library="Keep This" name="Keep This">
<c library="c4" name="c4">
</c>
</kw>
<c library="c3" name="c3">
<c library="c4" name="c4">
</c>
</c>
</kw>
</kw>
lxml
или внешними процессорами .