Переместить весь элемент с помощью lxml.etree - PullRequest
9 голосов
/ 26 января 2012

Возможно ли в lxml, учитывая элемент, переместить всю вещь в другое место документа xml без необходимости читать все его дочерние элементы и создавать заново? Мой лучший пример - смена родителей. Я немного покопался в документах, но мне не повезло. Заранее спасибо!

Ответы [ 2 ]

18 голосов
/ 26 января 2012

.append, .insert и другие операции делают это по умолчанию

>>> from lxml import etree
>>> tree = etree.XML('<a><b><c/></b><d><e><f/></e></d></a>')
>>> node_b = tree.xpath('/a/b')[0]
>>> node_d = tree.xpath('/a/d')[0]
>>> node_d.append(node_b)
>>> etree.tostring(tree) # complete 'b'-branch is now under 'd', after 'e'
'<a><d><e><f/></e><b><c/></b></d></a>'
>>> node_f = tree.xpath('/a/d/e/f')[0] # Nothing stops us from moving it again
>>> node_f.append(node_a) # Now 'a' is deep under 'f'
>>> etree.tostring(tree)
'<a><d><e><f><b><c/></b></f></e></d></a>'

Будьте осторожны при перемещении узлов, имеющих хвостовой текст. В lxml хвостовой текст принадлежит узлу и перемещается вместе с ним. (Кроме того, когда вы удаляете узел, его хвостовой текст также удаляется)

>>> tree = etree.XML('<a><b><c/></b>TAIL<d><e><f/></e></d></a>')
>>> node_b = tree.xpath('/a/b')[0]
>>> node_d = tree.xpath('/a/d')[0]
>>> node_d.append(node_b)
>>> etree.tostring(tree)
'<a><d><e><f/></e><b><c/></b>TAIL</d></a>'

Иногда это желаемый эффект, но иногда вам нужно что-то подобное:

>>> tree = etree.XML('<a><b><c/></b>TAIL<d><e><f/></e></d></a>')
>>> node_b = tree.xpath('/a/b')[0]
>>> node_d = tree.xpath('/a/d')[0]
>>> node_a = tree.xpath('/a')[0]
>>> # Manually move text
>>> node_a.text = node_b.tail
>>> node_b.tail = None
>>> node_d.append(node_b)
>>> etree.tostring(tree)
>>> # Now TAIL text stays within its old place
'<a>TAIL<d><e><f/></e><b><c/></b></d></a>'
0 голосов
/ 26 января 2012

Вы можете использовать методы .append(), .insert() для добавления подэлемента к существующему элементу:

>>> from lxml import etree
>>> from_ = etree.fromstring("<from/>")
>>> to  = etree.fromstring("<to/>")
>>> to.append(from_)
>>> etree.tostring(to)
'<to><from/></to>'
...