使用元素树删除xml节点的所有内容和子元素

我有一个 XML 文件,想删除具有给定属性=值的节点内的所有内容,但一直无法使元素树.remove()方法起作用。我得到一个list.remove(x): x not in list错误。


如果我有一个包含多个段落和列表元素的 div,v1-9,deleted我希望能够删除整个 div 及其所有内容的属性。


import xml.etree.ElementTree as ET

#get target file

tree = ET.parse('tested.htm')

#pull into element tree

root = tree.getroot()

#confirm output

print(root)

#define xlmns tags

MadCap = {'MadCap': 'http://www.madcapsoftware.com/Schemas/MadCap.xsd'}


i=1

j=6


# specify state

            state = "state.deleted-in-vers"

            # specify version

            vers = "version-number.v{}-{}".format(i,j)

            # combine to get conditional string might need to double up b/c of order mattering here???

            search = ".//*[@MadCap:conditions='{},{}']".format(vers,state)

            #get matching elements

            for elem in root.findall(search, MadCap):

                print('---PARENT---')

                print(elem)

                print('attributes:', elem.attrib)

                print('text:', elem.text)

                elem.text = " "

                elem.attrib = {}

                for child in elem.iter():

                    print('-child element-')

                    print(child)

                    elem.remove(child)

            print('==========')

为简单起见,我在上面省略了 i 和 j 上的循环。


这是目标 xml 的片段,因此您可以看到如何使用这些属性。


猛跑小猪
浏览 82回答 1
1回答

慕神8447489

我发现使用lxml更容易完成任务,因为更容易删除元素。试试下面的代码:from lxml import etree as etdef remove_element(el):&nbsp; &nbsp; parent = el.getparent()&nbsp; &nbsp; if el.tail.strip():&nbsp; &nbsp; &nbsp; &nbsp; prev = el.getprevious()&nbsp; &nbsp; &nbsp; &nbsp; if prev is not None:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prev.tail = (prev.tail or '') + el.tail&nbsp; &nbsp; &nbsp; &nbsp; else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; parent.text = (parent.text or '') + el.tail&nbsp; &nbsp; parent.remove(el)# Read source XMLparser = et.XMLParser(remove_blank_text=True)tree = et.parse('Input.xml', parser)root = tree.getroot()# Replace the below namespace with your proper onens = {'mc': 'http://dummy.com'}# Processingfor it in root.findall('.//*[@mc:conditions]', ns):&nbsp; &nbsp; attr = it.attrib&nbsp; &nbsp; attrTxt = ', '.join([ f'{key}: {value}'&nbsp; &nbsp; &nbsp; &nbsp; for key, value in attr.items() ])&nbsp; &nbsp; print(f'Elem.: {et.QName(it).localname:6}: {attrTxt}')&nbsp; &nbsp; delFlag = False&nbsp; &nbsp; cond = attr.get('{http://dummy.com}conditions')&nbsp; &nbsp; if cond:&nbsp; &nbsp; &nbsp; &nbsp; dct = { k: v for k, v in (x.split('.')&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for x in cond.split(',')) }&nbsp; &nbsp; &nbsp; &nbsp; vn = dct.get('version-number')&nbsp; &nbsp; &nbsp; &nbsp; st = dct.get('state')&nbsp; &nbsp; &nbsp; &nbsp; if vn == 'v1-6' and st.startswith('deleted'):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delFlag = True&nbsp; &nbsp; &nbsp; &nbsp; print(f"&nbsp; &nbsp; {vn}, {st:15}&nbsp; {'Delete' if delFlag else 'Keep'}")&nbsp; &nbsp; &nbsp; &nbsp; if delFlag:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; remove_element(it)# Print the resultprint(et.tostring(tree, method='xml',&nbsp; &nbsp; encoding='unicode', pretty_print=True))当然,在目标版本中添加将此树保存到输出文件。为了使用单个根元素正确格式化 XML,我将您的内容封装在:<main xmlns:MadCap="http://dummy.com">&nbsp; &nbsp;...</main>编辑在我以前的解决方案中,我曾经it.getparent().remove(it)删除有问题的元素。但后来我发现了一个缺陷,如果源 XML 包含“混合内容”,即被删除元素之后的“尾部”文本也被删除(但它不应该),这个缺陷就会变得可见。为了防止它,我添加了remove_element函数以仅删除元素本身并调用它而不是以前的it.getparent().remove(it)。评论中问题后的解释attrTxt的来源是attr字典的内容(当前元素的属性)。这个片段实际上打印了这本没有大括号的字典。它仅用于跟踪,无处可寻。另一方面,dct扮演着更重要的角色。它的来源是cond,包含(当前元素的)条件属性的内容,例如state.new-in-vers,version-number.v1-6。这段代码:在逗号上拆分内容。将上述每个部分拆分为一个点。从这些对创建字典。然后vn收到版本号 (&nbsp;v1-6&nbsp;) 和st&nbsp;- 状态 (&nbsp;new-in-vers&nbsp;)。这是嵌入这里的重要情报。由于这两个片段可能以不同的顺序出现,因此您无法创建任何匹配所有可能情况的XPath表达式。但是如果你检查上面的变量,这个元素是否应该被删除就变得很明显了。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python