С помощью Python извлеките в файл Excel значение ячейки в строке, где ячейка в той же строке содержит строку символов из XML-файла

У меня есть несколько XML-файлов с такими именами, как:

LLL_ABC0D012_title.xml

LLL_ABC0D013_title.xml

LLL_ABT0G012_title.xml

LLL_ABR0N012_title.xml

После «LLL_» всегда есть 8 символов.

У меня есть файл Excel с более чем 900 строками, который выглядит следующим образом:

ссылка dtp1 dtp2 dtp3 ABC0D012 1_блабла 1_1_блаблабла 1_1_1_блаблаблабла ABC0D013 1_блабла 1_1_блаблабла 1_1_1_блаблаблабла ABC0D014 1_блабла 1_1_блаблабла 1_1_1_блаблаблабла АБТ0G012 1_блабла 1_1_блаблабла 1_1_1_блаблаблабла

В моих XML-файлах есть теги <dtp1>text</dtp1>, <dtp2>text</dtp2>, <dtp3>text</dtp3>. Я хотел бы изменить текст этих тегов с текстом в ячейках соответствующих столбцов в таблице выше.

Для этого я бы хотел, чтобы мой сценарий выполнял цикл, который считывает символы ABC0D012 (а затем другие) в заголовке моего XML-файла, находит совпадение в столбце «Ссылка» моего файла Excel, а затем ищет соответствующее значение. в «dtp1», «dtp2» и «dtp3». Затем я хотел бы сохранить эти значения в переменной, чтобы заменить текст в моих тегах.

Я новичок в Python. Я попробовал что-то вроде:

import numpy as np
import openpyxl
import pandas as pd
import xml.etree.ElementTree as ET
import os

table1 = pd.read_excel('C:/Users/Documents/datatypes.xlsx', na_values=['NA'])
table2 = table1.replace('\xa0', ' ',regex=True)

for root, dirs, files in os.walk("."):
    for file in files :
        if file[-4:] == '.xml':
            #print(file)
            xml = ET.parse('LLL_ABC0D012_title.xml')
            root = xml.getroot()
            dtp1_xml = root[8]
            dtp2_xml = root[9]          
            dtp3_xml = root[10]
            num = file[4:12]
            #print(num)
            dtp1_excel = table2['dtp1'].where(table2['reference'] == num)
            dtp1_xml.text = dtp1_excel
            #print(dtp1_xml.text)
            ET.indent(root)
            xml.write("LLL_ABC0D012_title.xml", encoding='utf-8', xml_declaration=True, method='xml')

Но это не работает, «dtp1_excel» не возвращает значение dtp1 из таблицы в функции печати, а что-то вроде:

0      NaN
1      NaN
2      NaN
3      NaN
4      NaN
      ...
931    NaN
932    NaN
933    NaN
934    NaN
935    NaN
Name: dtp1, Length: 936, dtype: object

У меня нет значения NaN в столбцах reference и dtp1, и оно должно возвращать только одно значение ячейки.

Что не так с моим подходом? Не могли бы вы мне помочь, пожалуйста ?

Возможно, сначала используйте print()print(type(...)), print(len(...)) и т. д.), чтобы увидеть, какая часть кода выполняется и что на самом деле у вас есть в переменных. Он называется "print debugging" и помогает увидеть, что на самом деле делает код.

furas 24.06.2024 17:09

сначала проверьте, что у вас всего table1, затем, что у вас есть table2 и т. д. Возможно, вы сделали что-то для удаления значений. ИЛИ, может быть, проблема в том, когда вы это читаете. ИЛИ, может быть, ваш num неправильный - например. в нем могут быть дополнительные пробелы, которые он не отображает, ИЛИ, возможно, ваши данные имеют строки в нижнем регистре, но имя файла имеет верхний регистр. и т. д.

furas 24.06.2024 17:11

возможно, проблема приводит к where() - и, возможно, вам следует использовать table2['dtp1', table2['reference'] == num], а затем получить первый элемент из результата - потому что он всегда будет давать DataFrame или Series (даже если у него один результат или ноль результатов)

furas 24.06.2024 17:17

Почему вы импортируете openpyxl, если вместо этого вы используете pandas для чтения строки Excel для задания? См. также здесь или вы можете получить значения ячеек напрямую по ключу, doc

Hermann12 25.06.2024 07:30
Почему в 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
4
78
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Основная проблема заключается в том, что .where() возвращает все строки
и он помещает NaN в строки, которые не совпали, и сохраняет значения в строках, которые совпали.

Например

import pandas as pd

data = {
    'X': ['A','B','C'], 
    'Y': ['D','E','F'], 
    'Z': ['G','H','I']
}

df = pd.DataFrame(data)

df['X'].where(df['Y'] == 'E') дает

0    NaN
1      B
2    NaN
Name: X, dtype: object

но df['X'][df['Y'] == 'E'] дает

1    B
Name: X, dtype: object

Но все же есть другая проблема: оба дают Series, и все равно нужно использовать [index] или .iloc[row_number], чтобы получить единственное значение.

results = df['X'][df['Y'] == 'E']
print(results[1])       # row's index is `1`
print(results.iloc[0])  # row's numer is `0`

Полный рабочий пример:

import pandas as pd

data = {
    'X': ['A','B','C'], 
    'Y': ['D','E','F'], 
    'Z': ['G','H','I']
}

df = pd.DataFrame(data)

print('---')
print(df)

print("--- [df['Y'] == 'E'] ---")
results = df['X'][df['Y'] == 'E']
print(results)
print('type:', type(results))

print("--- .where(df['Y'] == 'E') ---")
results = df['X'].where(df['Y'] == 'E')
print(results)
print('type:', type(results))

results = df['X'][df['Y'] == 'E']

print("---")
print('     [1]:', results[1])
print('.iloc[0]:', results.iloc[0])

И у вас та же проблема — вам может понадобиться код без .where() и с .iloc[0]

dtp1_excel = table2['dtp1'][table2['reference'] == num].iloc[0]

Если вам нужно сравнить с большим количеством значений, вы можете использовать

( ... == ... ) & (... == ...)

df['X'][ (df['Y'] == 'E') & (df['Y'] == 'F']) ]

или .isin()

df['X'][ df['Y'].isin(['E', 'F']) ]
dtp1_excel = table2['dtp1'][ table2['reference'] == num] работает, но в конце num не всегда имеет одинаковое количество символов. Знаете ли вы, как я могу добавить функцию «или», например dtp1_excel = table2['dtp1'][ table2['reference'] == (num1 or num2 or num3)]? «num2» и «num3» — другие варианты длины «num». Я пробовал это, но это не работает. Спасибо !
Camille 25.06.2024 16:00

возможно, вам следует использовать .isin(dataset) или .str.contains(text), чтобы проверить, есть ли в столбце какая-то часть строки. Pandas имеет множество функций.

furas 25.06.2024 16:05

Код item == (num1 or num2 or num3) никогда не работает. Всегда нужно item == num1 or item == num2 or item == num3 в конце концов item in (num1, num2, num3). Но у Панды для этого есть item.isin([num1, num2, num3])

furas 25.06.2024 16:07

Я добавил примеры в ответ (в конце)

furas 25.06.2024 16:19
.isin([num1, num2, num3]) кажется работает! Еще раз, спасибо.
Camille 25.06.2024 16:22

Вот решение без панд. Я использую openpyxl то, что вы тоже импортируете, но не используете. Может быть имеет смысл измененные XML-файлы записать в другую папку? Я только переименовал его здесь:

from openpyxl import load_workbook
import xml.etree.ElementTree as ET
import os
  
def row_values(row_id, col_w=4):
    val_list = []
    for col in range(col_w):
        val_list.append(ws[row_id][col].value)
    return val_list

def change_xml(filename, data_list):
    root= ET.parse(filename).getroot()
    root[8].text = data_list[1]
    root[9].text = data_list[2]
    root[10].text = data_list[3]
    tree = ET.ElementTree(root)
    ET.indent(root, space='  ')
    tree.write(f"Changed_{data_list[0]}.xml", encoding='utf-8', xml_declaration=True, method='xml')
    print(f"Changed_{data_list[0]}.xml finished!")


wb = load_workbook("datatypes.xlsx")
ws = wb.active # if you have only one sheet take the active
print("Work sheet title:", ws.title)
#ws = wb['Tabelle1']
       
files = os.listdir(path='./')
for f in files:
    if "LLL" in f: # Because proceeded XML will written in same directory
        for cell in ws['A']: # iterate about the column 'A' of the Excel
           if f.endswith(".xml") and cell.value in f:
               print("Parsed file: ", f)
               change_xml(f, row_values(cell.row))

Поскольку я не знаю вашей структуры XML, я использовал этот фиктивный файл:

<?xml version = "1.0" encoding = "utf-8"?>
<root>
  <dummy />
  <dummy />
  <dummy />
  <dummy />
  <dummy />
  <dummy />
  <dummy />
  <dummy />
  <dtp1></dtp1>
  <dtp2></dtp2>
  <dtp3></dtp3>
</root>

Выход:

<?xml version='1.0' encoding='utf-8'?>
<root>
  <dummy />
  <dummy />
  <dummy />
  <dummy />
  <dummy />
  <dummy />
  <dummy />
  <dummy />
  <dtp1>1_blabla</dtp1>
  <dtp2>1_1_blablabla</dtp2>
  <dtp3>1_1_1_blablablabla</dtp3>
</root>

Спасибо за вашу помощь. Я новичок и не привык def, я собираюсь использовать решение Furas, чтобы быстро выполнить свою работу, но я попробую ваше предложение на практике и скажу вам, удалось ли мне это сделать.

Camille 25.06.2024 16:27

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