XML и, возможно, проблема с LXML

У меня есть много файлов 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>

Я хотел бы извлечь определенные значения из этих файлов XML. Итак, я собрал с помощью людей приведенный ниже код, который должен работать:

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? Или, может быть, проблема с lxml? Кто-нибудь знает, как к этому подойти?

В идеале результат должен выглядеть так

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

Пространство является результатом моего процесса копирования-вставки. XML-файлы не имеют места в самом начале. И все остальные теги тоже присутствуют, я скопировал только часть файлов, чтобы дать вам представление о том, как это выглядит.

energyMax 09.04.2023 16:26

@energyMax, можете ли вы добавить точный ожидаемый фрейм данных (соответствующий вашему вводу)?

Timeless 09.04.2023 16:30

Вы используете etree.XML(xml.encode()) вместо парсера? xmls это пути к файлам, а не содержимое xml

LMC 09.04.2023 16:37

Весь код представлен выше.

energyMax 09.04.2023 16:38

Тогда может в этом проблема. Вы должны использовать parse().

LMC 09.04.2023 16:39
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
5
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий
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

energies = ["xml", "energy_e", "energy_en", "energy_to"]
rows = []
for xml in xmls:
    row = []
    id = "xml-"+str(xmls.index(xml)+1)
    row.append(id)
    with open(xml, 'r', encoding='utf-8') as f:
        xml_string = f.read()
    root = etree.XML(xml_string.encode())
    
    for energy in energies[1:]:
        target = root.xpath(f'//energent[./sifra = "{energy}"]/vrednost/text()')
        row.extend(target if len(target)>0 else ["0"])
    rows.append(row)

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

разобрать ниже

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


energies = ["xml", "energy_ge", "energy_en", "energy_dteu", "energy_dtlb"]
rows = []
for xml in xmls:
    row = []
    id = "xml-"+str(xmls.index(xml)+1)
    row.append(id)
    root = etree.parse(xml)
    
    for energy in energies[1:]:
        target = root.xpath(f'//energent[./sifra[. = "{energy}"]]/vrednost/text()')
        row.extend( target if len(target)>0 else "0" )
    rows.append(row)

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

Это решит вашу проблему?

Meher Khurana 09.04.2023 16:26

Еще нет. Играет ли какую-то роль то, что сначала есть energenti и только потом energent. Так что energenti выше их всех... Я получаю такое же предупреждение даже сейчас

energyMax 09.04.2023 16:32

Я отредактировал сообщение, чтобы лучше решить вашу проблему и ответить на ваш новый вопрос. Пожалуйста, скажите мне, решит ли это вашу проблему.

Meher Khurana 09.04.2023 16:39

Не могли бы вы дать весь код в виде дырки? Я немного запутался в некоторых частях atm

energyMax 09.04.2023 16:44

Хорошо, дайте мне одну минуту, чтобы собрать его.

Meher Khurana 09.04.2023 16:45

Я также могу сделать это с помощью синтаксического анализа, поскольку это жизнеспособное решение.

Meher Khurana 09.04.2023 16:50

хорошо, вот оба кода

Meher Khurana 09.04.2023 16:52

Поскольку вы ищете фрейм данных, вы можете просто использовать read_xml от pandas:

df = (
    pd.read_xml(xml, xpath = ".//energent")
        .drop("naziv", axis=1)
        .set_index("sifra").T
        .rename_axis(None, axis=1)
)

И вот как вы можете включить его в свой код:

xmls = glob.glob("*.xml")

list_dfs = []
for idx, xml in enumerate(xmls, start=1):
    tmp_df = (
        pd.read_xml(xml, xpath = ".//energent")
            .drop("naziv", axis=1)
            .set_index("sifra").T
            .rename_axis(None, axis=1)
    )
    tmp_df.insert(0, "xml", f"{xml}-{idx}")
    list_dfs.append(tmp_df)
    
df = pd.concat(list_dfs, ignore_index=True)

​ Тест/выход (x3 тот же xml):

print(df) 

            xml  energy_e  energy_to  energy_en
0   first.xml-1    238981      16359          0
1  second.xml-2    238981      16359          0
2   third.xml-3    238981      16359          0

Можно пожалуйста весь код? Я (очевидно) не очень хорошо разбираюсь в питоне, поэтому не могу понять всей логики.

energyMax 09.04.2023 16:45

Я обновил свой ответ, можете ли вы его проверить?

Timeless 09.04.2023 16:48
NameError: name 'StringIO' is not defined это ошибка
energyMax 09.04.2023 16:50

Это потому, что я использовал io для чтения xml, я исправил код.

Timeless 09.04.2023 16:52

Другие вопросы по теме