使用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格式,所以触发语法错误。
解决方法
修正代码中的两个关键问题:
- 用
etree.parse()读取XML文件,再获取根节点,而不是直接解析文件名。 - 调整
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
相关产品推荐
相关产品推荐

