Разбор XML в Python, чтобы получить все дочерние элементы - PullRequest
0 голосов
/ 03 июля 2018

Я проанализировал XML-файл, чтобы получить все его элементы. Я получаю следующий вывод

[<Element '{urn:mitel:params:xml:ns:yang:vld}vld-list' at 0x0000000003059188>, <Element '{urn:mitel:params:xml:ns:yang:vld}vl-id' at 0x00000000030689F8>, <Element '{urn:mitel:params:xml:ns:yang:vld}descriptor-version' at 0x0000000003068A48>]

Мне нужно выбрать значение между} и 'только для каждого элемента списка.

Это мой код до сих пор:

import xml.etree.ElementTree as ET  
tree = ET.parse('UMR_VLD01_OAM_V6-Provider_eth0.xml')  
root = tree.getroot()

# all items
print('\nAll item data:')
for elem in root:  
    all_descendants = list(elem.iter())
    print(all_descendants)

Как мне этого добиться?

1 Ответ

0 голосов
/ 04 июля 2018

Текст в {} является частью пространства имен квалифицированного имени (QName) элемента XML. AFAIK, в ElementTree нет способа вернуть только локальное имя . Итак, вы должны либо

  • извлечение локальной части имени с помощью обработки строк, как уже предлагалось в комментарии к вашему вопросу,
  • используйте lxml.etree вместо xml.etree.ElementTree и применяйте xpath('local-name()') для каждого элемента,
  • или предоставить источник XML без пространства имен. Вы можете удалить пространство имен с помощью XSLT.

Итак, учитывая этот ввод XML:

<?xml version="1.0" encoding="UTF-8"?>
<foo xmlns="urn:mitel:params:xml:ns:yang:vld">
    <bar>
        <baz x="1"/>
        <yet>
            <more>
                <nested/>
            </more>
        </yet>
    </bar>
    <bar/>
</foo>

Вы можете распечатать список локальных имен только с этим вариантом вашей программы:

import xml.etree.ElementTree as ET  
tree = ET.parse('UMR_VLD01_OAM_V6-Provider_eth0.xml')  
root = tree.getroot()

# all items
print('\nAll item data:')
for elem in root:
    all_descendants = [e.tag.split('}', 1)[1] for e in elem.iter()]
    print(all_descendants)

Вывод:

['bar', 'baz', 'yet', 'more', 'nested']
['bar']

Версия с lxml.etree и xpath('local-name()') выглядит следующим образом:

import lxml.etree as ET
tree = ET.parse('UMR_VLD01_OAM_V6-Provider_eth0.xml')  
root = tree.getroot()

# all items
print('\nAll item data:')
for elem in root:
    all_descendants = [e.xpath('local-name()') for e in elem.iter()]
    print(all_descendants)

Вывод такой же, как и в версии обработки строк.


Для полного удаления пространства имен из вашего ввода вы можете применить этот XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Тогда ваши оригинальные программные выходы:

[<Element 'bar' at 0x04583B40>, <Element 'baz' at 0x04583B70>, <Element 'yet' at 0x04583BD0>, <Element 'more' at 0x04583C30>, <Element 'nested' at 0x04583C90>]
[<Element 'bar' at 0x04583CC0>]

Теперь элементы сами не несут пространства имен. Так что тебе больше не нужно это раздевать.

Вы можете применить XSLT с помощью xsltproc, тогда вам не нужно менять свою программу. Кроме того, вы можете применять XSLT в python , но для этого также необходимо использовать lxml.etree. Итак, последний вариант вашей программы выглядит так:

import lxml.etree as ET

tree = ET.parse('UMR_VLD01_OAM_V6-Provider_eth0.xml')  
xslt = ET.parse('stripns.xslt')
transform = ET.XSLT(xslt)
tree = transform(tree)

root = tree.getroot()
# all items
print('\nAll item data:')
for elem in root:
    all_descendants = list(elem.iter())
    print(all_descendants)
...