我正在寻找一种遍历XML文件并将元素标签/文本组合成字符串的方法。 XML文件是配置导出。我已经尝试过使用iter()方法,但是它并不能完全按照我需要的方式工作。这是原始的XML。这些示例出于可读性而被截断。
<Configuration product="Cisco Codec" version="ce9.8.0.be9359915d0" apiVersion="4">
<Audio>
<DefaultVolume valueSpaceRef="/Valuespace/INT_0_100">70</DefaultVolume>
<Input>
<HDMI item="3" maxOccurrence="1">
<Level valueSpaceRef="/Valuespace/INT_-24_0">-12</Level>
<Mode valueSpaceRef="/Valuespace/TTPAR_OnOff">On</Mode>
<VideoAssociation>
<MuteOnInactiveVideo valueSpaceRef="/Valuespace/TTPAR_OnOff">On</MuteOnInactiveVideo>
</VideoAssociation>
</HDMI>
....
这些值最终将转换为字符串
Audio DefaultVolume: 70
Audio Input HDMI 3 Level: -12
Audio Input HDMI 3 Mode: On
Audio Input HDMI 3 VideoAssociation MuteOnInactiveVideo: On
...
XML具有多种设置类别。例如Video Input 2 RGB: On
,因此我无法对搜索字符串进行硬编码。最终,我希望遍历每个元素并打印出父元素标签以及最终的元素文本。有一个一致的模式,其中父元素不包含值,最后一个元素包含设置值。
这可以使用lxml和xpath完成:
audio = """[your xml above, fixed"""] #the xml in your example was invalid because closing tags were missing
from lxml import etree
doc = etree.XML(audio.encode('utf-8'))
items = doc.xpath('//Audio//*')
for item in items:
ancs = []
if len(item.text.strip())>0:
for anc in item.iterancestors():
ancs.append(anc.tag)
if anc.tag == "HDMI":
ancs.append(anc.xpath('./@item')[0])
ancs = ancs [:-1]
ancs.reverse()
print(' '.join(ancs),item.tag,':',item.text.strip())
输出:
Audio DefaultVolume : 70
Audio Input 3 HDMI Level : -12
Audio Input 3 HDMI Mode : On
Audio Input 3 HDMI VideoAssociation MuteOnInactiveVideo : On
定义以下功能:
def getParentNames(nd):
res = []
while True:
itm = nd.attrib.get('item')
if itm is not None:
res.append(itm)
res.append(nd.tag) # Current tag name
nd = nd.getparent() # Go 1 level up
if nd is nd.getroottree().getroot(): # Stop before the root node
res.reverse()
return ' '.join(res)
它以空格分隔的列表形式返回所有父节点的名称,但是如果某些节点具有item属性,此属性的值被添加到此列表。
我注意到您只是通过这种“特殊方式”踩下了[[item属性,所以这就是为什么我只选择上述解决方案。
然后打印所有leaf节点的上述“路径”和文本值:
for nd in root.iter():
if len(nd.getchildren()) == 0: # Leaf nodes only
print(f'{getParentNames(nd)}: {nd.text}')