#python #pandas #dataframe
Вопрос:
Это моя XML-строка, я получаю это как сообщение, так что это не файл
<?xml version="1.0" encoding="UTF-8"?>
<OperationStatus xmlns:ns2="summaries">
<EventId>123456</EventId>
<notificationId>123456</notificationId>
<userDetails>
<clientId>client_1</clientId>
<userId>user_1</userId>
<groupIds>
<groupId>123456</groupId>
<groupId>123457</groupId>
</groupIds>
</userDetails>
</OperationStatus>
Я хочу получить вывод в формате ниже
message,code,Id
Я упомянул только три элемента, но у меня может быть гораздо больше элементов .
Вот как я пытаюсь, но не получаю точного результата
Я начал изучать Python, так что извините меня за глупые ошибки
from __future__ import print_function
import pandas as pd
def lambda_handler():
import xml.etree.ElementTree as et
xtree = et.parse('''<?xml version="1.0" encoding="UTF-8"?>
<OperationStatus xmlns:ns2="summaries">
<EventId>123456</EventId>
<notificationId>123456</notificationId>
<userDetails>
<clientId>client_1</clientId>
<userId>user_1</userId>
<groupIds>
<groupId>123456</groupId>
<groupId>123457</groupId>
</groupIds>
</userDetails>
</OperationStatus>''')
xroot = xtree.getroot()
df_cols = ["message", "code", "Id"]
rows = []
for node in xroot:
s_name = node.attrib.get("message")
s_mail = node.find("code").text if node is not None else None
s_grade = node.find("Id").text if node is not None else None
lambda_handler()
Комментарии:
1. Как создается ваш фрейм данных? Какова цель
lambda_handler
этого ?
Ответ №1:
вы можете попробовать использовать XPath, так будет проще получить нужные данные
import xml.etree.ElementTree as et
import pandas as pd
xtree = et.fromstring("""<?xml version="1.0" encoding="UTF-8"?>
<name xmlns:ns2="summaries">
<message>5jb10x5rf7sp1fov5msgoof7r</message>
<code>COMPLETED</code>
<Id>dfkjlhgd98568y</Id>
</name>""")
keys = ["message", "code", "Id"]
data = {k: [xtree.find(".//" k).text] for k in keys}
print(pd.DataFrame(data))
# Outputs:
# message code Id
# 0 5jb10x5rf7sp1fov5msgoof7r COMPLETED dfkjlhgd98568y
Комментарии:
1. Это не работает, если у нас есть два уровня xml-элемента . я нашел это простое решение, но должно ли
.//
оно играть роль, если у нас многослойный xml ?
Ответ №2:
Это тот результат, которого вы хотите?
# !pip install xmltodict
import xmltodict
xml = """
<name xmlns:ns2="summaries">
<message>5jb10x5rf7sp1fov5msgoof7r</message>
<code>COMPLETED</code>
<Id>dfkjlhgd98568y</Id>
</name>
"""
d = xmltodict.parse(xml)
print(d['name']['message'])
print(d['name']['code'])
print(d['name']['Id'])
Выход
5jb10x5rf7sp1fov5msgoof7r
COMPLETED
dfkjlhgd98568y
Более xmltodict
подробная информация на сайте https://github.com/martinblech/xmltodict
Ответ №3:
Учитывая вашу строку:
your_string='''
<?xml version="1.0" encoding="UTF-8"?>
<name xmlns:ns2="summaries">
<message>5jb10x5rf7sp1fov5msgoof7r</message>
<code>COMPLETED</code>
<Id>dfkjlhgd98568y</Id>
</name>'''
Поскольку это строка, вы бы использовали .fromstring (), а не .parse(). Это автоматически находит корневой узел name
для вас (т. Е. Не нужно звонить .getroot()
):
root = et.fromstring(your_string)
>>> root
<Element 'name' at 0x1050f51d0>
Как только у вас будет структура данных с name
корнем, вы можете либо выполнить итерацию по подэлементам:
df_cols = ["message", "code", "Id"]
for node in root:
if node.tag in df_cols:
print({node.tag:node.text})
С принтами:
{'message': '5jb10x5rf7sp1fov5msgoof7r'}
{'code': 'COMPLETED'}
{'Id': 'dfkjlhgd98568y'}
Или вы можете использовать запрос xpath для поиска каждого интересующего элемента:
for k in df_cols:
print({k:root.find(f'./{k}').text})
# same output
Теперь, поскольку фрейм данных может быть построен с помощью {key:[list_of_elements],...}
, вы можете построить этот тип диктата из того, что мы построили здесь:
df=pd.DataFrame({k:[root.find(f'./{k}').text] for k in df_cols})
Если у вас несколько элементов, используйте findall
:
df=pd.DataFrame({k:[x.text for x in root.findall(f'./{k}')] for k in df_cols})