You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用lxml解析XML遇XMLSyntaxError,如何提取指定数据?

XML批量提取数据报错问题解决

问题描述

有多个结构如下的XML文件:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<reixmlprenos>
  <Qfl>1808</Qfl>
  <fOVE>13.7</fOVE>
  <NetoVolumen>613</NetoVolumen>
  <Hv>104.2</Hv>
  <energenti>
    <energent>
      <sifra>energy_e</sifra>
      <naziv>EE [kWh]</naziv>
      <vrednost>238981</vrednost>
    </energent>
    <energent>
      <sifra>energy_to</sifra>
      <naziv>Do</naziv>
      <vrednost>16359</vrednost>
    </energent>
    <energent>
      <sifra>energy_en</sifra>
      <naziv>En</naziv>
      <vrednost>0</vrednost>
    </energent>
</energenti>
  <rei>
    <zavetrovanost>2</zavetrovanost>
    <cone>
      <cona>
        <cona_id>1</cona_id>
        <cc_si_cona>1110000</cc_si_cona>
        <visina_cone>2.7</visina_cone>
        <dolzina_cone>14</dolzina_cone>
      </cona>
      <cona>
        <cona_id>2</cona_id>
        <cc_si_cona>120000</cc_si_cona>
      </cona>
  </rei>
</reixmlprenos>

尝试用pandas和lxml编写代码提取指定字段值,代码如下:

import pandas as pd
import glob
import os
from lxml import etree


os.chdir(r'R:\...\XML-1122_test')
dir_path = glob.glob('*.xml')
xmls = dir_path


#note: For simplicity, I'm using the well formed version of the xml strings in your question; you'll have to use actual file names and paths
energies = ["xml", "energy_ge", "energy_en", "energy_dteu", "energy_dtlb"]
#I just made up some names - you'll have to use actual names, of course; the first one is for the file identifier - see below
rows = []
for xml in xmls:
    row = []
    id = "xml-"+str(xmls.index(xml)+1)
    #this creates the file identifier
    row.append(id)
    root = etree.XML(xml.encode())
    #in real life, you'll have to use the parse() method
    
    for energy in energies[1:]:
        #the '[1:]' is used to skip the first "energy"; it's only used as the file identifier
        target = root.xpath(f'//energent[./sifra[.="{energy}"]]/vrednost/text()')
        #note the use of f-strings
        row.extend( target if len(target)>0 else "0" )
    rows.append(row)

print(pd.DataFrame(rows,columns=energies))

运行时报错:

File "<string>", line 1
XMLSyntaxError: Start tag expected, '<' not found, line 1, column 1

需要解决报错,并得到如下格式的结果:

xml       energy_e   energy_en   energy_to
xml-1    238981      0         16539 
xml-2    ...         ..        .. 

错误原因

这是lxml使用错误,和XML文件本身无关。代码中etree.XML(xml.encode())是把文件名(字符串)当成XML内容解析,文件名显然不是合法的XML格式,所以触发语法错误。

解决方法

修正代码中的两个关键问题:

  1. 用etree.parse()读取XML文件,再获取根节点,而不是直接解析文件名。
  2. 调整energies列表为实际需要提取的字段,同时处理参数类型(extend需传入列表,不能直接传字符串"0")。

修正后的代码:

import pandas as pd
import glob
import os
from lxml import etree


os.chdir(r'R:\...\XML-1122_test')
xml_files = glob.glob('*.xml')

# 调整为实际需要提取的字段,第一个是文件标识列
energies = ["xml", "energy_e", "energy_en", "energy_to"]
rows = []

for idx, xml_file in enumerate(xml_files, start=1):
    row = [f"xml-{idx}"]  # 生成文件标识
    # 正确读取XML文件并获取根节点
    tree = etree.parse(xml_file)
    root = tree.getroot()
    
    for energy in energies[1:]:
        # 查找对应sifra的vrednost值
        target = root.xpath(f'//energent[sifra/text()="{energy}"]/vrednost/text()')
        # 存在值则取第一个,否则填0
        row.append(target[0] if target else "0")
    
    rows.append(row)

# 生成DataFrame并打印
df = pd.DataFrame(rows, columns=energies)
print(df)

额外优化说明

  • 用enumerate替代xmls.index(xml),效率更高且避免文件名重复时的索引错误。
  • 优化XPath表达式,简化为//energent[sifra/text()="{energy}"]/vrednost/text(),逻辑更清晰。
  • 改用row.append()直接添加单个值,避免extend拆分字符串的问题。

内容的提问来源于stack exchange,提问作者energyMax

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 19:02:47