从 xml 中获取价值

Grab value from xml

首先我要说我是编写代码的新手。我一直在尝试从 xml 文件中获取信息,但我可能会添加失败。 xml 文件中的一个小片段如下:

<?xml version="1.0"?>
<AlertRequestType xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <DateTime xmlns="http://EU/Common/20181/">2021-06-15T08:55:08.441</DateTime>
  <Code xmlns=>A68</Code>
  <UniqueAlertId xmlns="http://EU/20181/">US-8I2-NVH-7JH-0A1- 
   54M</UniqueAlertId>
  <Message xmlns="http://EU/Common/20181/">B-Id mismatch.</Message>
  <Source xmlns="http://EU/2556781/">National S I</Source>
  <SupportingData xmlns="http://EMVS.EU/Common/20181/">
    <Item key="errorcode" value="A68" />
    <Item key="errormessage" value="B-Id mismatch." />
    <Item key="date" value="2021-06-15" />
    <Item key="time" value="21:35:03" />
    <Item key="uniquealertid" value="US-8I2-NVH-7JH-0A1-54M" />
    <Item key="productcode" value="988356696047773" />
    <Item key="serialnumber" value="PFL72KBN85S22" />
    <Item key="b-id" value="QD88223402+G+1332" />
   </SupportingData>
</AlertRequestType>

现在,作为一个对 ElementTree 和一般编码理解很差的人,我的问题是: 如何从特定的“

下面是我尝试修改以满足我的需要的代码,但遗憾的是没有成功。

import xml.etree.ElementTree as ET                                                        
import os                                                                                 
                                                                                          
xmlfile = 'xmltest.xml'                                                              
fullfile = os.path.abspath(os.path.join('filer', xmlfile))                                
                                                                                          
tree = ET.parse(fullfile)                                                                 
root = tree.getroot()                                                                     
ET.dump(tree)                                                                             
                                                                                          
for elm in root.findall("./SupportingData/Item key/errorcode[@value=]"):                  
    print(elm.attrib)                                                                     

同样,此代码来自完全不熟悉编码的人。 如果有人能帮助我,我将永远感激不已!

首先我们需要修复作为示例提供的XML:

<?xml version="1.0"?>
<AlertRequestType xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <DateTime xmlns="http://EU/Common/20181/">2021-06-15T08:55:08.441</DateTime>
  <Code xmlns="">A68</Code> <!-- Closing xmlns attribute -->
  <UniqueAlertId xmlns="http://EU/20181/">US-8I2-NVH-7JH-0A1- 
   54M</UniqueAlertId>
  <Message xmlns="http://EU/Common/20181/">B-Id mismatch.</Message>
  <Source xmlns="http://EU/2556781/">National S I</Source>
  <SupportingData xmlns="http://EMVS.EU/Common/20181/">
    <Item key="errorcode" value="A68" />
    <Item key="errormessage" value="B-Id mismatch." />
    <Item key="date" value="2021-06-15" />
    <Item key="time" value="21:35:03" />
    <Item key="uniquealertid" value="US-8I2-NVH-7JH-0A1-54M" />
    <Item key="productcode" value="988356696047773" />
    <Item key="serialnumber" value="PFL72KBN85S22" />
    <Item key="b-id" value="QD88223402+G+1332" />
   </SupportingData>
</AlertRequestType>

其次,我建议您使用一个更简单的库,下面的代码完全符合您的要求:

import os
import xml.dom.minidom                                                                     
                                                                                      
if __name__ == "__main__":
    xmlfile = 'xmltest.xml'                                                              
    fullfile = os.path.abspath(os.path.join('filer', xmlfile))      
    doc = xml.dom.minidom.parse(fullfile)
    items = doc.getElementsByTagName("Item")
    for i in items:
        print("Key:" + i.getAttribute("key"))
        print("Value:" + i.getAttribute("value"))

输出为:

Key:errorcode
Value:A68
Key:errormessage
Value:B-Id mismatch.
Key:date
Value:2021-06-15
Key:time
Value:21:35:03
Key:uniquealertid
Value:US-8I2-NVH-7JH-0A1-54M
Key:productcode
Value:988356696047773
Key:serialnumber
Value:PFL72KBN85S22
Key:b-id
Value:QD88223402+G+1332

我已经给出了针对你的问题的解决方案,但我建议你创建一个名为 XMLReader 的 Class 并在其中添加所有 XML 您想要的操作。

你问题中的 XML 不可能被解析 - 我假设 XML 与@Bruno 显示的相同。下次您 post 在这里提问时,请确保您问题中的数据(和代码)有效。

Minidom 可能是解决您眼前问题的一种方法,但总的来说,我认为 ElementTree 有更好的 xml 支持,尽管如果您需要更复杂的 xpath,那么 lxml 或其他库更好。

无论如何,为了解决您的具体问题,您的 xpath 不起作用的第一个原因是因为您的 xml 使用了命名空间。

专门针对您的 xml 这一行指定下面的标签位于命名空间 http://EMVS.EU/Common/20181/

<SupportingData xmlns="http://EMVS.EU/Common/20181/">

你的 xpath 无法工作的第二个原因是 Item key/errorcode[@value=] 是不正确的 xpath 语法 - 这应该是 Item[@key='errorcode'] 但命名空间问题意味着你没有达到目的这可能无法匹配或可能导致异常。

所以您的 xpath 需要在 {} 中为标记包含命名空间,否则它将不匹配。这有效:

for elm in root.findall("./{http://EMVS.EU/Common/20181/}SupportingData/{http://EMVS.EU/Common/20181/}Item[@key='errorcode']"):
    print(elm)
    print(elm.attrib)

使用命名空间时,可能很难使 xpath 字符串起作用。当您开始尝试匹配一长串 tags/attributes 时,您不知道哪个位不匹配。我的方法非常简单:首先让第一个 xpath 部分匹配,即:

for elm in root.findall("./{http://EMVS.EU/Common/20181/}SupportingData"):

检查它是否有效 - 在第一个 xpath 有效之前,没有必要添加更多内容,然后添加下一个匹配项,检查它是否有效,添加下一个匹配项,等等。这样当 xpath 不匹配时,它就是你的部分刚刚补充说这就是问题所在。

还有其他匹配命名空间的方法,例如提供命名空间字典并像 findall('role:character', ns) 那样使用它 - 在 ElementTree 文档中有示例 https://python.readthedocs.io/en/stable/library/xml.etree.elementtree.html

如果您不打算写出 XML 并且没有在多个名称空间中使用标签,另一种方法可能非常方便,就是简单地从标签中删除所有名称空间,也可能从属性。请在此处查看@nonagon 和我自己如何执行此操作的示例 Python ElementTree module: How to ignore the namespace of XML files to locate matching element when using the method "find", "findall"