在多个 XML 文件的子字段中提取数据

Extract data in subfields of multiple XML files

提问人:energyMax 提问时间:11/4/2022 更新时间:11/4/2022 访问量:243

问:

我的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_zp</sifra>
      <naziv>Zemeljski plin [kWh]</naziv>
      <vrednost>22482</vrednost>
    </energent>
    <energent>
      <sifra>energy_lb</sifra>
      <naziv>Lesna biomasa [kg]</naziv>
      <vrednost>20482</vrednost>
    </energent>
  <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>

对于几个 1,000 个 XML 文件,我想从每个文件中读取某些值并将其放入 df 中。我当前的代码如下所示:

import pandas as pd
import glob
import os

podatki = ['Qfl','Hv']

os.chdir(r'C:\Users\...\XMLs')
dir_path = glob.glob('*.xml')
#print(dir_path)

datoteka = (dir_path)

#print(datoteka)

df = pd.concat((pd.read_xml(file, xpath='//reiXmlPrenos')[podatki] for file in datoteka))
df['datoteka'] = datoteka
df = df.set_index('datoteka')
print(df)

这很好用。但问题是子类别下的数据。例如 和。<energent><cc_si_cona>

我想要一个看起来像这样的 df:

datoteka  Qfl  Hv    energy_zp  energy_elko  energy_lb  cc_si_cona-1  cc_si_cona-2
xml1     1808  104.2  22482        2482         20482      1110000      120000

我的尝试如下,但失败了。

import pandas as pd
import glob
import os

podatki = ['Qfl','Hv']

podatki2 = ['sifra']

os.chdir(r'C:\Users\...\XMLs')
dir_path = glob.glob('*.xml')
#print(dir_path)

datoteka = (dir_path)

#print(datoteka)

df = pd.concat((pd.read_xml(file, xpath='//reiXmlPrenos')[podatki] for file in datoteka))
df['datoteka'] = datoteka
df = df.set_index('datoteka')
print(df)

df2 = pd.concat((pd.read_xml(file, xpath='//reiXmlPrenos/energenti/energent')[podatki2] for file in datoteka))
df2['datoteka'] = datoteka
df2 = df2.set_index('datoteka2')
print(df2)

所以我尝试创建一个具有不同根的单独 df,稍后合并 df-s。但是我收到一个警告:

ValueError: Length of values (6) does not match length of index (16)
python pandas xml 分组 HTML 解析

评论

0赞 LMC 11/4/2022
尝试检查 DF。值可能已经存在。df = pd.read_xml(file, xpath='//reiXmlPrenos')
0赞 energyMax 11/4/2022
@LMC 没有运气。错误状态 也许还有其他想法吗?:(KeyError: "['cc_si_cona'] not in index"

答:

0赞 energyMax 11/4/2022 #1

我使用以下代码取得了进展:

import xml.etree.ElementTree as ETree
import pandas as pd

xmldata = r"C:\...\S1.xml"
prstree = ETree.parse(xmldata)
root = prstree.getroot()


# print(root)
store_items = []
all_items = []

for storeno in root.iter('energent'):
    
    cona_sifra = storeno.find('sifra').text
    cona_vrednost = storeno.find('vrednost').text


    store_items = [cona_sifra, cona_naziv, cona_vrednost]
    all_items.append(store_items)

xmlToDf = pd.DataFrame(all_items, columns=[
'sifra', 'naziv', 'vrednost'])

print(xmlToDf.to_string(index=False))

这导致:

    sifra        vrednost
 energy_e         238981
energy_to          16359

这对于 1 个示例来说很好。但是我有 1,000 个 XML 文件,希望 1) 将每个 XML 的所有结果都放在 1 行中,2) 区分不同的“sifra”代码。

例如,可以有energy_e, energy_en, energy_to

因此,理想情况下,最终的 df 将如下所示

xml     e-sifra  e-vrednost en-sifra  en-vrednost to-naziv  to-vrednost
xml-name1 energy_e    238981      0         0         energy_to  16539
xml-name2...

这可以进一步简化为:

xml       energy_e   energy_en   energy_to
xml-name    238981      0         16539 

能做到吗?

评论

0赞 energyMax 11/4/2022
@LMZ这也许是要走的路吗?
0赞 energyMax 11/4/2022
@Сергей Кох 这也许是要走的路吗?
0赞 energyMax 11/4/2022
@СергейКох这也许是要走的路吗?
0赞 LMC 11/4/2022
是的,ElementTree 是保留数据然后填充数据帧的不错选择,