遍历XML以找到绝对路径

问题描述 投票:0回答:2

我正在寻找一种遍历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,因此我无法对搜索字符串进行硬编码。最终,我希望遍历每个元素并打印出父元素标签以及最终的元素文本。有一个一致的模式,其中父元素不包含值,最后一个元素包含设置值。

python-3.x elementtree
2个回答
0
投票

这可以使用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

0
投票

定义以下功能:

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}')
© www.soinside.com 2019 - 2024. All rights reserved.