Выполните итерацию по XML, чтобы найти абсолютный путь - PullRequest
0 голосов
/ 20 апреля 2020

Я ищу способ просмотреть файл 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, поэтому я не могу жестко закодировать строки поиска. В конце дня я собираюсь пройтись по каждому элементу и распечатать теги родительского элемента, а также текст последнего элемента. Существует согласованный шаблон родительских элементов, которые не содержат значений, тогда последний элемент содержит значение настроек.

Ответы [ 2 ]

0 голосов
/ 20 апреля 2020

Здесь лучше использовать l xml.

Определить следующую функцию:

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 это «особый способ», поэтому я выбрал только вышеприведенное решение.

Но если у вас есть другие «исключения», касающиеся особой обработки некоторых атрибутов, измените вышеуказанную функцию соответствующим образом.

Затем выведите вышеприведенные «пути» и текстовые значения всех листьев узлов:

for nd in root.iter():
    if len(nd.getchildren()) == 0:  # Leaf nodes only
        print(f'{getParentNames(nd)}: {nd.text}')

Результат:

Audio DefaultVolume: 70
Audio Input HDMI 3 Level: -12
Audio Input HDMI 3 Mode: On
Audio Input HDMI 3 VideoAssociation MuteOnInactiveVideo: On
0 голосов
/ 20 апреля 2020

Это можно сделать с помощью l xml и 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
...