【问题标题】:ElementTree: Parsing XML great-grandchildren [duplicate]ElementTree:解析 XML 曾孙 [重复]
【发布时间】:2016-12-21 00:37:34
【问题描述】:

我已经尝试解析一些 XML 几个小时了,但没有成功。检查了类似的线程并查看了 ElementTree 文档,但仍然很迷茫。

基本上,我从一个存储在字符串中的路由器接收一些 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>"""

例如,我想要获取/打印内容的节点是 rt-destination。

我试过了:

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")

任何有关如何遍历此特定节点或如何获得所需结果的帮助将不胜感激。

【问题讨论】:

    标签: python xml automation elementtree


    【解决方案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

    【讨论】:

      【解决方案2】:

      您缺少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,但是,下一层及其下的所有内容都属于未命名(空)命名空间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 为键的命名空间。现在您可以使用 xpath 搜索 rt-destination 标记并仅返回标记内的文本。

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

      【讨论】:

        猜你喜欢
        • 2021-02-08
        • 1970-01-01
        • 2017-07-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-25
        • 2021-02-06
        • 2017-08-31
        相关资源
        最近更新 更多