파이썬의 lxml을 사용하여 속성의 내용을 기반으로 요소를 완전히 제거해야합니다. 예:
import lxml.etree as et
xml="""
<groceries>
<fruit state="rotten">apple</fruit>
<fruit state="fresh">pear</fruit>
<fruit state="fresh">starfruit</fruit>
<fruit state="rotten">mango</fruit>
<fruit state="fresh">peach</fruit>
</groceries>
"""
tree=et.fromstring(xml)
for bad in tree.xpath("//fruit[@state=\'rotten\']"):
#remove this element from the tree
print et.tostring(tree, pretty_print=True)
다음을 인쇄하고 싶습니다.
<groceries>
<fruit state="fresh">pear</fruit>
<fruit state="fresh">starfruit</fruit>
<fruit state="fresh">peach</fruit>
</groceries>
다음과 같이 임시 변수를 저장하고 수동으로 인쇄하지 않고이를 수행 할 수있는 방법이 있습니까?
newxml="<groceries>\n"
for elt in tree.xpath('//fruit[@state=\'fresh\']'):
newxml+=et.tostring(elt)
newxml+="</groceries>"
답변
remove
xmlElement 의 메소드를 사용하십시오 .
tree=et.fromstring(xml)
for bad in tree.xpath("//fruit[@state=\'rotten\']"):
bad.getparent().remove(bad) # here I grab the parent of the element to call the remove directly on it
print et.tostring(tree, pretty_print=True, xml_declaration=True)
@Acorn 버전과 비교해야한다면 제거 할 요소가 xml의 루트 노드 바로 아래에 있지 않아도 작동합니다.
답변
당신은 remove
기능을 찾고 있습니다. 트리의 remove 메서드를 호출하고 제거 할 하위 요소를 전달합니다.
import lxml.etree as et
xml="""
<groceries>
<fruit state="rotten">apple</fruit>
<fruit state="fresh">pear</fruit>
<punnet>
<fruit state="rotten">strawberry</fruit>
<fruit state="fresh">blueberry</fruit>
</punnet>
<fruit state="fresh">starfruit</fruit>
<fruit state="rotten">mango</fruit>
<fruit state="fresh">peach</fruit>
</groceries>
"""
tree=et.fromstring(xml)
for bad in tree.xpath("//fruit[@state='rotten']"):
bad.getparent().remove(bad)
print et.tostring(tree, pretty_print=True)
결과:
<groceries>
<fruit state="fresh">pear</fruit>
<fruit state="fresh">starfruit</fruit>
<fruit state="fresh">peach</fruit>
</groceries>
답변
한 가지 상황을 만났습니다.
<div>
<script>
some code
</script>
text here
</div>
div.remove(script)
의도 text here
하지 않은 부분을 제거합니다 .
여기에 대한 답변에 따라 param으로 etree.strip_elements
텍스트를 제거할지 여부를 제어 할 수있는 더 나은 솔루션 이라는 것을 알았습니다 with_tail=(bool)
.
하지만 여전히 이것이 태그에 xpath 필터를 사용할 수 있는지 모르겠습니다. 알리기 위해 이것을 넣으십시오.
다음은 문서입니다.
strip_elements (tree_or_element, * tag_names, with_tail = True)
제공된 태그 이름을 가진 모든 요소를 트리 또는 하위 트리에서 삭제합니다. 이렇게하면 모든 속성, 텍스트 콘텐츠 및 하위 항목을 포함하여 요소와 전체 하위 트리가 제거됩니다.
with_tail
키워드 인수 옵션을 명시 적 으로 False로 설정하지 않으면 요소의 꼬리 텍스트도 제거됩니다 .태그 이름은에서와 같이 와일드 카드를 포함 할 수 있습니다
_Element.iter
.일치하더라도 전달한 요소 (또는 ElementTree 루트 요소)는 삭제되지 않습니다. 그 후손 만 취급합니다. 루트 요소를 포함하려면이 함수를 호출하기 직전에 태그 이름을 확인하십시오.
사용 예 ::
strip_elements(some_element, 'simpletagname', # non-namespaced tag '{http://some/ns}tagname', # namespaced tag '{http://some/other/ns}*' # any tag from a namespace lxml.etree.Comment # comments )
답변
이미 언급했듯이이 remove()
메서드를 사용 하여 트리에서 (하위) 요소를 삭제할 수 있습니다 .
for bad in tree.xpath("//fruit[@state=\'rotten\']"):
bad.getparent().remove(bad)
그러나 tail
HTML과 같은 혼합 콘텐츠 문서를 처리하는 경우 문제가 되는를 포함하는 요소를 제거합니다 .
<div><fruit state="rotten">avocado</fruit> Hello!</div>
된다
<div></div>
나는 당신이 항상 원하지 않는 것을 가정합니다 🙂 요소 만 제거하고 꼬리를 유지하는 도우미 함수를 만들었습니다.
def remove_element(el):
parent = el.getparent()
if el.tail.strip():
prev = el.getprevious()
if prev:
prev.tail = (prev.tail or '') + el.tail
else:
parent.text = (parent.text or '') + el.tail
parent.remove(el)
for bad in tree.xpath("//fruit[@state=\'rotten\']"):
remove_element(bad)
이렇게하면 꼬리 텍스트가 유지됩니다.
<div> Hello!</div>
답변
lxml의 html을 사용하여 해결할 수도 있습니다.
from lxml import html
xml="""
<groceries>
<fruit state="rotten">apple</fruit>
<fruit state="fresh">pear</fruit>
<fruit state="fresh">starfruit</fruit>
<fruit state="rotten">mango</fruit>
<fruit state="fresh">peach</fruit>
</groceries>
"""
tree = html.fromstring(xml)
print("//BEFORE")
print(html.tostring(tree, pretty_print=True).decode("utf-8"))
for i in tree.xpath("//fruit[@state='rotten']"):
i.drop_tree()
print("//AFTER")
print(html.tostring(tree, pretty_print=True).decode("utf-8"))
다음과 같이 출력되어야합니다.
//BEFORE
<groceries>
<fruit state="rotten">apple</fruit>
<fruit state="fresh">pear</fruit>
<fruit state="fresh">starfruit</fruit>
<fruit state="rotten">mango</fruit>
<fruit state="fresh">peach</fruit>
</groceries>
//AFTER
<groceries>
<fruit state="fresh">pear</fruit>
<fruit state="fresh">starfruit</fruit>
<fruit state="fresh">peach</fruit>
</groceries>