我有以下xml输出:
<?xml version='1.0' encoding='ISO-8859-1'?>
<?xml-stylesheet type='text/xsl' href='image_metadata_stylesheet.xsl'?>
<dataset>
<images>
<image file='VideoExtract/testset/10224.jpg'>
<box top='436' left='266' width='106' height='61'>
<label>1</label>
</box>
</image>
<image file='VideoExtract/testset/1044.jpg'>
<box top='507' left='330' width='52' height='27'>
<label>2</label>
</box>
</image>
<image file='VideoExtract/testset/10675.jpg'>
</image>
</images>
</dataset>
由此,我想删除所有没有子节点的节点。例如,图像内的第三个图像节点没有子节点。如何删除此子节点。期望的输出将是
<?xml version='1.0' encoding='ISO-8859-1'?>
<?xml-stylesheet type='text/xsl' href='image_metadata_stylesheet.xsl'?>
<dataset>
<images>
<image file='VideoExtract/testset/10224.jpg'>
<box top='436' left='266' width='106' height='61'>
<label>1</label>
</box>
</image>
<image file='VideoExtract/testset/1044.jpg'>
<box top='507' left='330' width='52' height='27'>
<label>2</label>
</box>
</image>
</images>
</dataset>
我尝试了以下方法,但它没有帮助。
from lxml import etree as ET
root = ET.parse('testxml.xml')
for child in root.iterfind('targetElement'):
if(len(child.attrib) < 1 and len(child) < 1):
child.getparent().remove(child)
答案 0 :(得分:2)
由于您使用lxml
模块,请考虑XSLT,这是专门用于转换XML文件的专用语言。使用这种方法,不需要for
循环或if
逻辑。
实际上,您的XML看起来按照处理指令使用XSLT,因此您可以在该样式表中包含以下脚本。以下脚本在任何<image>
标记上运行Identity Transform和一个空模板,其中包含零个子项。空模板会删除此类节点。
XSLT (另存为.xsl文件)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="image[count(*)=0]"/>
</xsl:stylesheet>
<强>的Python 强>
import lxml.etree as et
doc = et.parse('Input.xml')
xsl = et.parse('XSLT_Script.xsl')
transform = et.XSLT(xsl)
result = transform(doc)
# OUTPUT TO SCREEN
print(result)
# OUTPUT TO FILE
with open('Output.xml', 'wb') as f:
f.write(result)
<强>输出强>
<?xml version="1.0"?>
<?xml-stylesheet type='text/xsl' href='image_metadata_stylesheet.xsl'?><dataset>
<images>
<image file="VideoExtract/testset/10224.jpg">
<box top="436" left="266" width="106" height="61">
<label>1</label>
</box>
</image>
<image file="VideoExtract/testset/1044.jpg">
<box top="507" left="330" width="52" height="27">
<label>2</label>
</box>
</image>
</images>
</dataset>
答案 1 :(得分:1)
此代码可能完全符合您在问题中提出的要求。我怀疑这正是你想要的。
>>> from lxml import etree
>>> tree = etree.parse('testxml.xml')
>>> for el in tree.iter():
... el.tag, len(list(el.iterchildren()))
... if not len(list(el.iterchildren())):
... parent = el.getparent()
... if parent is not None:
... parent.remove(el)
...
('dataset', 1)
('images', 3)
('image', 1)
('box', 1)
('label', 0)
('image', 1)
('box', 1)
('label', 0)
('image', 0)
>>> tree.write('temp.xml', pretty_print=True)
这是生成的xml文件。
<?xml-stylesheet type='text/xsl' href='image_metadata_stylesheet.xsl'?>
<dataset>
<images>
<image file="VideoExtract/testset/10224.jpg">
<box top="436" left="266" width="106" height="61">
</box>
</image>
<image file="VideoExtract/testset/1044.jpg">
<box top="507" left="330" width="52" height="27">
</box>
</image>
</images>
</dataset>
我注意到label
个节点不包含任何节点(尽管它们包含文本!);因此,输出中缺少它们。 这是你真正想要的吗?
相比之下,此版本的代码会保留label
元素。
>>> tree = etree.parse('testxml.xml')
>>> for el in tree.iter():
... if len(list(el.iterchildren())) or ''.join([_.strip() for _ in el.itertext()]):
... pass
... else:
... parent = el.getparent()
... if parent is not None:
... parent.remove(el)
这是这种情况下的结果文件。
<?xml-stylesheet type='text/xsl' href='image_metadata_stylesheet.xsl'?>
<dataset>
<images>
<image file="VideoExtract/testset/10224.jpg">
<box top="436" left="266" width="106" height="61">
<label>1</label>
</box>
</image>
<image file="VideoExtract/testset/1044.jpg">
<box top="507" left="330" width="52" height="27">
<label>2</label>
</box>
</image>
</images>
</dataset>