2016-08-14 5 views
0

Я пытаюсь разобрать некоторые XML на пару часов без везения. Проверял аналогичные темы и просмотрел документы ElementTree и все еще довольно потерял.ElementTree: Разборчивость правнуков XML

В принципе, я получаю XML-вывод от маршрутизатора, который хранится в строке, что я, в свою очередь, должен анализировать какую-то конкретную информацию.

Вот пример XML-я работаю:

xml = """<rpc-reply xmlns:junos="http://xml.juniper.net/junos/14.1D0/junos"> 
     <route-information xmlns="http://xml.juniper.net/junos/14.1D0/junos-routing"> 
      <!-- keepalive --> 
      <route-table> 
       <table-name>inet.0</table-name> 
       <destination-count>52</destination-count> 
       <total-route-count>52</total-route-count> 
       <active-route-count>52</active-route-count> 
       <holddown-route-count>0</holddown-route-count> 
       <hidden-route-count>0</hidden-route-count> 
       <rt junos:style="brief"> 
        <rt-destination>5.5.5.5/32</rt-destination> 
        <rt-entry> 
         <active-tag>*</active-tag> 
         <current-active/> 
         <last-active/> 
         <protocol-name>Direct</protocol-name> 
         <preference>0</preference> 
         <age junos:seconds="428929">4d 23:08:49</age> 
         <nh> 
          <selected-next-hop/> 
          <via>lo0.0</via> 
         </nh> 
        </rt-entry> 
       </rt> 
      </route-table> 
     </route-information> 
     <cli> 
      <banner></banner> 
     </cli> 
</rpc-reply>""" 

Например, узел Я хотел бы получить к/печать содержимого является к.т.-назначения.

Я пробовал:

root = ET.fromstring(xml) 

values = root.find('rt') 
for element in values: 
    print element.text 

Этот,

value= root.find('rt-destination') 

print value 

И это, чтобы установить корень (указатель?) На конкретном узле,

x = root.getiterator(tag = "destination-count") 

Любая помощь относительно того, как переход к этому конкретному узлу или как добраться до желаемого результата будет очень оценен.

ответ

1

Вам не хватает пространства имен для тега route-information. В вашем XML у вас есть 2 пространства имен, к сожалению, тот, который вам нужен, не помечен.

<rpc-reply xmlns:junos="http://xml.juniper.net/junos/14.1D0/junos"> 
    <route-information xmlns="http://xml.juniper.net/junos/14.1D0/junos-routing"> 

rpc-reply падает под пространством имен junos, однако, следующий слой и все под ним подпадает под безымянными (NULL) пространства имен xmlns="http://xml.juniper.net/junos/14.1D0/junos-routing".

с использованием root.nsmap предоставляет следующий словарь пространств имен для корневого слоя: {'junos': 'http://xml.juniper.net/junos/14.1D0/junos'}. Таким образом, чтобы получить доступ к rt элементов в этом пространстве имен вы будете использовать:

root.find('junos:rt', namespaces=root.nsmap) 

Однако в следующем слое lxml.etree известно о пространстве имен "http://xml.juniper.net/junos/14.1D0/junos-routing", а потому, что он не имеет меток, он извлекает его на карту пространства имен с None как ключ словаря.

>>> nsmap = root.getchildren()[0].nsmap 
>>> nsmap 
{'junos': 'http://xml.juniper.net/junos/14.1D0/junos', 
None: 'http://xml.juniper.net/junos/14.1D0/junos-routing'} 

Ну, это проблема, потому что мы не можем ссылаться на пространство имен с помощью None. Один из вариантов - просто создать новую ссылку на пространство имен в словаре для 'http://xml.juniper.net/junos/14.1D0/junos-routing'.

nsmap['my_ns'] = nsmap.pop(None) 

Мы должны использовать .pop здесь, потому что lxml не позволяет использовать пространство имен с None в качестве ключа. Теперь вы можете найти тег rt-destination с помощью xpath и вернуть только текст в теге.

root.xpath('.//my_ns:rt-destination/text()', namespaces=nsmap) 
1

Причина, по которой код не работает, объясняется пространством имён. Если пространство имен всегда то же самое, вы можете кодировать его в качестве префикса к тегу, который вы пытаетесь найти:

import xml.etree.ElementTree as ET 

xml = """ 
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/14.1D0/junos"> 
    <route-information xmlns="http://xml.juniper.net/junos/14.1D0/junos-routing"> 
     <!-- keepalive --> 
     <route-table> 
      <table-name>inet.0</table-name> 
      <destination-count>52</destination-count> 
      <total-route-count>52</total-route-count> 
      <active-route-count>52</active-route-count> 
      <holddown-route-count>0</holddown-route-count> 
      <hidden-route-count>0</hidden-route-count> 
      <rt junos:style="brief"> 
       <rt-destination>5.5.5.5/32</rt-destination> 
       <rt-entry> 
        <active-tag>*</active-tag> 
        <current-active/> 
        <last-active/> 
        <protocol-name>Direct</protocol-name> 
        <preference>0</preference> 
        <age junos:seconds="428929">4d 23:08:49</age> 
        <nh> 
         <selected-next-hop/> 
         <via>lo0.0</via> 
        </nh> 
       </rt-entry> 
      </rt> 
     </route-table> 
    </route-information> 
    <cli> 
     <banner></banner> 
    </cli> 
</rpc-reply> 
""" 

XML_NAMESPACE = '{http://xml.juniper.net/junos/14.1D0/junos-routing}' 
root = ET.fromstring(xml) 
rt_nodes = root.iter(tag='{}rt-destination'.format(XML_NAMESPACE)) 
print rt_nodes.next().text # 5.5.5.5/32 

Если вам нужно что-то более гибкое, вы можете проверить ответы here.

 Смежные вопросы

  • Нет связанных вопросов^_^