【问题标题】:How to parse XML from string in python如何从python中的字符串解析XML
【发布时间】:2021-11-25 20:50:58
【问题描述】:

我正在尝试从 Python 中的字符串解析 XML,但没有成功。 我要解析的字符串是:

<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:573a453c-72c0-4185-8c54-9010593dd102">
   <data>
      <config xmlns="http://www.calix.com/ns/exa/base">
         <profile>
            <policy-map>
               <name>ELINE_PM_1</name>
               <class-map-ethernet>
                  <name>Eth-match-any-1</name>
                  <ingress>
                     <meter-type>meter-mef</meter-type>
                     <eir>1000000</eir>
                  </ingress>
               </class-map-ethernet>
            </policy-map>
            <policy-map>
               <name>ELINE_PM_2</name>
               <class-map-ethernet>
                  <name>Eth-match-any-2</name>
                  <ingress>
                     <meter-type>meter-mef</meter-type>
                     <eir>10000000</eir>
                  </ingress>
               </class-map-ethernet>
            </policy-map>
         </profile>
      </config>
   </data>
</rpc-reply>

我正在尝试使用 xml.etree.ElementTree 库来解析 xml,并且我还尝试删除与 xml 版本和编码相关的第一行,但没有结果。重现我面临的问题的代码 sn-p 是:

import xml.etree.ElementTree as ET

reply_xml='''
<data>
   <config>
      <profile>
         <policy-map>
            <name>ELINE_PM_1</name>
            <class-map-ethernet>
               <name>Eth-match-any-1</name>
               <ingress>
                  <meter-type>meter-mef</meter-type>
                  <eir>1000000</eir>
               </ingress>
            </class-map-ethernet>
         </policy-map>
         <policy-map>
            <name>ELINE_PM_2</name>
            <class-map-ethernet>
               <name>Eth-match-any-2</name>
               <ingress>
                  <meter-type>meter-mef</meter-type>
                  <eir>10000000</eir>
               </ingress>
            </class-map-ethernet>
         </policy-map>
      </profile>
   </config>
</data>
'''

root = ET.fromstring(reply_xml)
for child in root:
    print(child.tag, child.attrib)

reply_xml 是一个包含上述 xml 的字符串,因此它应该可以工作,但是如果我使用调试器检查根变量,我发现它没有被正确填充。 似乎第一个 xml 标记 (&lt;?xml version="1.0" encoding="UTF-8"?&gt;) 会产生一些问题,但即使我手动删除它,我也无法正确解析 xml。

有什么线索可以解析那个 xml 吗?

【问题讨论】:

  • 你想从这个xml中收集什么信息?
  • &lt;?xml .. ?&gt; 部分不是标签,而是 XML 声明。而 ElementTree 可以完美处理。
  • 我要收集的信息是标签。此示例中有两个不同,但可能不止两个
  • 我无法重现这个。我得到输出“config {}”,这是正确的。使用完整的 XML,我得到“{urn:ietf:params:xml:ns:netconf:base:1.0}data {}”。
  • 你是如何获取字符串的? (不要说你是从 XML 文件中读取的)

标签: python xml parsing xml-parsing


【解决方案1】:

您的原始 XML 具有名称空间。您需要在 XPath 查询中尊重它们。

import xml.etree.ElementTree as ET

reply_xml '''<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:573a453c-72c0-4185-8c54-9010593dd102">
   <data>
      <config xmlns="http://www.calix.com/ns/exa/base">
        <!-- ... the rest of it ... -->
      </config>
   </data>
</rpc-reply>'''

ns = {
    'calix': 'http://www.calix.com/ns/exa/base'
}

root = ET.fromstring(reply_xml)
for eir in root.findall('.//calix:eir', ns):
    print(eir.text)

打印

1000000 10000000

【讨论】:

    【解决方案2】:

    见下文(1 个带 xpath 的内衬)

    import xml.etree.ElementTree as ET
    
    reply_xml='''
    <data>
       <config>
          <profile>
             <policy-map>
                <name>ELINE_PM_1</name>
                <class-map-ethernet>
                   <name>Eth-match-any-1</name>
                   <ingress>
                      <meter-type>meter-mef</meter-type>
                      <eir>1000000</eir>
                   </ingress>
                </class-map-ethernet>
             </policy-map>
             <policy-map>
                <name>ELINE_PM_2</name>
                <class-map-ethernet>
                   <name>Eth-match-any-2</name>
                   <ingress>
                      <meter-type>meter-mef</meter-type>
                      <eir>20000000</eir>
                   </ingress>
                </class-map-ethernet>
             </policy-map>
          </profile>
       </config>
    </data>
    '''
    
    root = ET.fromstring(reply_xml)
    eirs = [e.text for e in root.findall('.//eir')]
    print(eirs)
    

    输出

    ['1000000', '20000000']
    

    【讨论】:

      【解决方案3】:

      您的代码运行良好。它显示了根元素的所有子元素,只有&lt;config&gt; .. &lt;/config&gt;,它没有任何属性。

      要到达&lt;eir&gt;标签,你应该使用XPath,或者递归遍历树。

      XPath 的快速解决方案:

      root.findall('.//eir')
      

      【讨论】:

      • 非常感谢,它有效!
      • 那应该不行,OP 的原始 XML 有 XML 命名空间。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-17
      • 1970-01-01
      相关资源
      最近更新 更多