【问题标题】:Finding element in xml with python使用python在xml中查找元素
【发布时间】:2019-02-12 13:56:26
【问题描述】:

我试图在将其内容转换为列表然后转换为 CSV 之前解析 XML。不幸的是,我认为我查找初始元素的搜索词失败了,导致后续搜索在层次结构中进一步下降。我是 XML 新手,所以我尝试了命名空间字典的变体,包括命名空间引用......下面给出了简化的 XML:

<?xml version="1.0" encoding="utf-8"?>
<StationList xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
			xmlns:add="http://www.govtalk.gov.uk/people/AddressAndPersonalDetails" 
			xmlns:com="http://nationalrail.co.uk/xml/common"            xsi:schemaLocation="http://internal.nationalrail.co.uk/xml/XsdSchemas/External/Version4.0/nre-station-v4-0.xsd" 
			xmlns="http://nationalrail.co.uk/xml/station">
  <Station xsi:schemaLocation="http://internal.nationalrail.co.uk/xml/XsdSchemas/External/Version4.0/nre-station-v4-0.xsd">
    <ChangeHistory>
      <com:ChangedBy>spascos</com:ChangedBy>
      <com:LastChangedDate>2018-11-07T00:00:00.000Z</com:LastChangedDate>
    </ChangeHistory>
    <Name>Aber</Name>
  </Station>​

我用来尝试提取 com/...xml/station / ChangedBy 元素的代码如下

tree = ET.parse(rootfilepath + "NRE_Station_Dataset_2019_raw.xml")
root = tree.getroot()

#get at the tags and their data
#for elem in tree.iter():
#    print(f"this the tag {elem.tag} and this is the data: {elem.text}")

#open file for writing
station_data = open(rootfilepath + 'station_data.csv','w')

csvwriter = csv.writer(station_data)

station_head = []

count = 0
#inspiration for this code: http://blog.appliedinformaticsinc.com/how-to-  parse-and-convert-xml-to-csv-using-python/
#this is where it goes wrong; some combination of the namespace and the tag can't find anything in line 27, 'StationList'
for member in root.findall('{http://nationalrail.co.uk/xml/station}Station'):
station = []
if count == 0:
changedby = member.find('{http://nationalrail.co.uk/xml/common}ChangedBy').tag
station_head.append(changedby)

    name = member.find('{http://nationalrail.co.uk/xml/station}Name').tag
    station_head.append(name)

    count = count+1

changedby = member.find('{http://nationalrail.co.uk/xml/common}ChangedBy').text
station.append(changedby)

name = member.find('{http://nationalrail.co.uk/xml/station}Name').text
station.append(name)

csvwriter.writerow(station)

我试过了:

  • 使用命名空间字典,但结果一无所获
  • 使用硬编码命名空间,但会导致“属性错误:'NoneType' 对象没有属性 'tag'

提前感谢所有帮助。

【问题讨论】:

    标签: python xml parsing


    【解决方案1】:

    首先,您的 XML 无效(文件末尾没有&lt;/StationList&gt;)。

    假设您有有效的 XML 文件:

    <?xml version="1.0" encoding="utf-8"?>
    <StationList xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:add="http://www.govtalk.gov.uk/people/AddressAndPersonalDetails"
                xmlns:com="http://nationalrail.co.uk/xml/common"            xsi:schemaLocation="http://internal.nationalrail.co.uk/xml/XsdSchemas/External/Version4.0/nre-station-v4-0.xsd"
                xmlns="http://nationalrail.co.uk/xml/station">
      <Station xsi:schemaLocation="http://internal.nationalrail.co.uk/xml/XsdSchemas/External/Version4.0/nre-station-v4-0.xsd">
        <ChangeHistory>
          <com:ChangedBy>spascos</com:ChangedBy>
          <com:LastChangedDate>2018-11-07T00:00:00.000Z</com:LastChangedDate>
        </ChangeHistory>
        <Name>Aber</Name>
      </Station>​
    </StationList>
    

    然后您可以将您的 XML 转换为 JSON 并简单地将地址转换为所需的值:

    import xmltodict
    with open('file.xml', 'r') as f:
        data = xmltodict.parse(f.read())
    changed_by = data['StationList']['Station']['ChangeHistory']['com:ChangedBy']
    

    输出:

    spascos
    

    【讨论】:

    • 非常感谢。这是一个非常易读和优雅的解决方案。它通过一些调整解决了我的问题。因为我要遍历多个“站”,所以需要一个整数: data['StationList']['Station'][0]['ChangeHistory']['com:ChangedBy']... 这在python json type error无效的 xml 是由于我为简化 xml 进行了笨拙的编辑。
    • 我已经成功地使用了它,但是在完整的 XML 中还有更多层次的嵌套,我没有分享。我认为导航 5-8 级嵌套有序字典的指南会对我有所帮助。谁能指出我可以离开并尝试几种不同方法的参考点?谢谢大家。不想被勺子喂食,但要知道在哪里看。
    【解决方案2】:

    试试lxml:

    #!/usr/bin/env python3
    
    from lxml import etree
    
    ns = {"com": "http://nationalrail.co.uk/xml/common"}
    
    with open("so.xml") as f:
        tree = etree.parse(f)
        for t in tree.xpath("//com:ChangedBy/text()", namespaces=ns):
            print(t)
    

    输出:

    spascos
    

    【讨论】:

      【解决方案3】:

      您可以使用 Beautifulsoup,它是一个 html 和 xml 解析器

      from bs4 import BeautifulSoup
      
      fd = open(rootfilepath + "NRE_Station_Dataset_2019_raw.xml")  
      soup = BeautifulSoup(fd,'lxml-xml')
      
      for i in soup.findAll('ChangeHistory'):      
          print(i.ChangedBy.text)
      

      【讨论】:

      • 不幸的是,我所在的地方没有美味的汤,否则我会使用这种方法。
      • 我已经尝试过这种方法,但现在出现编码错误:UnicodeDecodeError: 'charmap' codec can't decode byte... at position。尝试像这样强制执行编码,没有帮助 soup = BeautifulSoup(fd,'lxml-xml',from_encoding='utf-8')
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-02-17
      • 2021-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-27
      相关资源
      最近更新 更多