Я пытаюсь удалить все «вложенные теги одного типа». Если для каждого элемента XML вы обнаружите в его поддереве другой подэлемент с таким же именем, удалите его тег (сохраните его содержимое). Другими словами, превратите <a>...<a>...</a>...</a> в <a>.........</a>.
Я создал очень красивый и простой фрагмент кода, используя функции iter и Strip_tags из пакета lxml:
import lxml.etree
root = lxml.etree.parse('book.txt')
for element in root.iter():
lxml.etree.strip_tags(element, element.tag)
print(lxml.etree.tostring(root).decode())
Я использовал этот входной файл:
<book>
<b><title>My <b>First</b> Book</title></b>
<i>Introduction <i><i>To</i></i> LXML</i>
<name><a>Author: <a>James</a></a></name>
</book>
и я получил этот вывод:
<book>
<b><title>My First Book</title></b>
<i>Introduction To LXML</i>
<name><a>Author: <a>James</a></a></name>
</book>
Как видите, удалены почти все вложенные теги, кроме одного: <a>Author: <a>James</a></a>. Что не так с кодом? Как я могу это исправить?
что, если у вас будет элемент, вложенный в уже вложенный элемент? Возможно, потребуется использовать рекурсию.
Возможно, сначала используйте print() (и print(type(...)), print(len(...)) и т. д.), чтобы увидеть, какая часть кода выполняется и что на самом деле у вас есть в переменных. Он называется "print debugging" и помогает увидеть, что на самом деле делает код.
когда я запускаю print( element.tag ) в for-цикле, я не показываю name и a. Вероятно, существует аналогичная проблема, например, с удалением элементов из списка при повторении списка.






Небезопасно изменять XML-дерево во время его итерации. Вместо этого переберите список всех элементов.
import lxml.etree
root = lxml.etree.parse('book.txt')
all_elements = list(root.iter())
for element in all_elements:
lxml.etree.strip_tags(element, element.tag)
print(lxml.etree.tostring(root).decode())
Выход:
<book>
<b><title>My First Book</title></b>
<i>Introduction To LXML</i>
<name><a>Author: James</a></name>
</book>
Это так умно и элегантно! Конечно, это может показаться очевидным тем, кто уже знает суть. Я не забуду сохранить «план итерации» в безопасности и в стороне, прежде чем начну вносить изменения. Спасибо.
См. также stackoverflow.com/q/3346696/407651
В XSLT это
<xsl:template match = "*[node-name() = ancestor::*/node-name()]">
<xsl:apply-templates/>
</xsl:template>
Просто здравый вопрос: поддерживает ли etree.iter() изменение дерева во время обхода?