Python 读取 xml 及相关子元素
Python read xml with related child elements
我有一个具有这种结构的 xml 文件:
<?DOMParser ?>
<logbook:LogBook xmlns:logbook="http://www/logbook/1.0" version="1.2">
<product>
<serialNumber value="764000606"/>
</product>
<visits>
<visit>
<general>
<startDateTime>2014-01-10T12:22:39.166Z</startDateTime>
<endDateTime>2014-03-11T13:51:31.480Z</endDateTime>
</general>
<parts>
<part number="03081" name="WSSA" index="0016"/>
</parts>
</visit>
<visit>
<general>
<startDateTime>2013-01-10T12:22:39.166Z</startDateTime>
<endDateTime>2013-03-11T13:51:31.480Z</endDateTime>
</general>
<parts>
<part number="02081" name="PSSF" index="0017"/>
</parts>
</visit>
</visits>
</logbook:LogBook>
我想从这个 xml 中得到两个输出:
1-访问包括序列号,所以我写:
import pandas as pd
import xml.etree.ElementTree as ET
tree = ET.parse(filename)
root=tree.getroot()
visits=pd.DataFrame()
for general in root.iter('general'):
for child in root.iter('serialNumber'):
visits=visits.append({'startDateTime':general.find('startDateTime').text ,
'endDateTime': general.find('endDateTime').text, 'serialNumber':child.attrib['value'] }, ignore_index=True)
此代码的输出是以下数据帧:
serialNumber | startDateTime | endDateTime
-------------|------------------------|------------------------|
764000606 |2014-01-10T12:22:39.166Z|2014-03-11T13:51:31.480Z|
764000606 |2013-03-11T13:51:31.480Z|2013-01-10T12:22:39.166Z|
2-份
对于 parts
,我希望得到以下输出,通过 startDateTime
区分访问,并且我想显示与每次访问相关的部分:
serialNumber | startDateTime|number|name|index|
-------------|--------------|------|----|-----|
我写的部分:
parts=pd.DataFrame()
for part in root.iter('part'):
for child in root.iter('serialNumber'):
parts=parts.append({'index':part.attrib['index'],
'znumber':part.attrib['number'],
'name': part.attrib['name'], 'serialNumber':child.attrib['value'], 'startDateTime':general.find('startDateTime').text}, ignore_index=True)
这是我从这段代码中得到的:
index |name|serialNumber| startDateTime |znumber|
------|----|------------|------------------------|-------|
0016 |WSSA| 764000606 |2013-01-10T12:22:39.166Z| 03081 |
0017 |PSSF| 764000606 |2013-01-10T12:22:39.166Z| 02081 |
虽然我想要这个:看看 startDateTime
:
index |name|serialNumber| startDateTime |znumber|
------|----|------------|------------------------|-------|
0016 |WSSA| 764000606 |2014-01-10T12:22:39.166Z| 03081 |
0017 |PSSF| 764000606 |2013-01-10T12:22:39.166Z| 02081 |
有什么想法吗?
我正在使用 XML ElementTree
尝试以下操作,
import xml.dom.minidom as minidom
doc = minidom.parse('filename')
memoryElem = doc.getElementsByTagName('part')[0]
print memoryElem.getAttribute('number')
print memoryElem.getAttribute('name')
print memoryElem.getAttribute('index')
希望对你有所帮助
这是一个从 xml.
获取数据的示例
code.py:
#!/usr/bin/env python3
import sys
import xml.etree.ElementTree as ET
from pprint import pprint as pp
file_name = "a.xml"
def get_product_sn(product_node):
for product_node_child in list(product_node):
if product_node_child.tag == "serialNumber":
return product_node_child.attrib.get("value", None)
return None
def get_parts_data(parts_node):
ret = list()
for parts_node_child in list(parts_node):
attrs = parts_node_child.attrib
ret.append({"number": attrs.get("number", None), "name": attrs.get("name", None), "index": attrs.get("index", None)})
return ret
def get_visit_node_data(visit_node):
ret = dict()
for visit_node_child in list(visit_node):
if visit_node_child.tag == "general":
for general_node_child in list(visit_node_child):
if general_node_child.tag == "startDateTime":
ret["startDateTime"] = general_node_child.text
elif general_node_child.tag == "endDateTime":
ret["endDateTime"] = general_node_child.text
elif visit_node_child.tag == "parts":
ret["parts"] = get_parts_data(visit_node_child)
return ret
def get_node_data(node):
ret = {"visits": list()}
for node_child in list(node):
if node_child.tag == "product":
ret["serialNumber"] = get_product_sn(node_child)
elif node_child.tag == "visits":
for visits_node_child in list(node_child):
ret["visits"].append(get_visit_node_data(visits_node_child))
return ret
def main():
tree = ET.parse(file_name)
root_node = tree.getroot()
data = get_node_data(root_node)
pp(data)
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
main()
备注:
- 它以树状方式处理 xml,因此它映射(如果您愿意)在 xml (如果xml结构发生变化,代码也要适配)
- 它被设计为通用的:get_node_data 可以在有 2 个子节点的节点上调用:product 和 访问次数。在我们的例子中,它是根节点本身,但在现实世界中,可能存在一系列这样的节点,每个节点都有我上面列出的 2 个子节点
- 它的设计易于出错,所以如果 xml 不完整,它会尽可能多地获取数据;我选择了这种(贪婪的)方法而不是遇到错误时它只是抛出异常的方法
- 因为我没有使用 pandas,而不是填充对象 我只是 return 一个 Python字典 (json);我认为将其转换为 DataFrame 应该不难
- 我 运行 它有 Python 2.7 和 Python 3.5
输出(包含 2 个键的字典)- 缩进以提高可读性:
- serialNumber - 序列号(很明显)
- visits(因为它是字典,所以我必须将此数据放在 "under" 键中)- 字典列表,每个字典都包含 访问节点
输出:
(py_064_03.05.04_test0) e:\Work\Dev\Whosebug\q045049761>"e:\Work\Dev\VEnvs\py_064_03.05.04_test0\Scripts\python.exe" code.py
Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32
{'serialNumber': '764000606',
'visits': [{'endDateTime': '2014-03-11T13:51:31.480Z',
'parts': [{'index': '0016', 'name': 'WSSA', 'number': '03081'}],
'startDateTime': '2014-01-10T12:22:39.166Z'},
{'endDateTime': '2013-03-11T13:51:31.480Z',
'parts': [{'index': '0017', 'name': 'PSSF', 'number': '02081'}],
'startDateTime': '2013-01-10T12:22:39.166Z'}]}
@EDIT0:添加了多个 part 节点处理,如评论之一所述.该功能已移至 get_parts_data。现在,visits 列表中的每个条目都有一个 parts 键,其值将是一个列表,该列表由从每个 中提取的字典组成part节点(提供的xml不是这种情况)。
我有一个具有这种结构的 xml 文件:
<?DOMParser ?>
<logbook:LogBook xmlns:logbook="http://www/logbook/1.0" version="1.2">
<product>
<serialNumber value="764000606"/>
</product>
<visits>
<visit>
<general>
<startDateTime>2014-01-10T12:22:39.166Z</startDateTime>
<endDateTime>2014-03-11T13:51:31.480Z</endDateTime>
</general>
<parts>
<part number="03081" name="WSSA" index="0016"/>
</parts>
</visit>
<visit>
<general>
<startDateTime>2013-01-10T12:22:39.166Z</startDateTime>
<endDateTime>2013-03-11T13:51:31.480Z</endDateTime>
</general>
<parts>
<part number="02081" name="PSSF" index="0017"/>
</parts>
</visit>
</visits>
</logbook:LogBook>
我想从这个 xml 中得到两个输出:
1-访问包括序列号,所以我写:
import pandas as pd
import xml.etree.ElementTree as ET
tree = ET.parse(filename)
root=tree.getroot()
visits=pd.DataFrame()
for general in root.iter('general'):
for child in root.iter('serialNumber'):
visits=visits.append({'startDateTime':general.find('startDateTime').text ,
'endDateTime': general.find('endDateTime').text, 'serialNumber':child.attrib['value'] }, ignore_index=True)
此代码的输出是以下数据帧:
serialNumber | startDateTime | endDateTime
-------------|------------------------|------------------------|
764000606 |2014-01-10T12:22:39.166Z|2014-03-11T13:51:31.480Z|
764000606 |2013-03-11T13:51:31.480Z|2013-01-10T12:22:39.166Z|
2-份
对于 parts
,我希望得到以下输出,通过 startDateTime
区分访问,并且我想显示与每次访问相关的部分:
serialNumber | startDateTime|number|name|index|
-------------|--------------|------|----|-----|
我写的部分:
parts=pd.DataFrame()
for part in root.iter('part'):
for child in root.iter('serialNumber'):
parts=parts.append({'index':part.attrib['index'],
'znumber':part.attrib['number'],
'name': part.attrib['name'], 'serialNumber':child.attrib['value'], 'startDateTime':general.find('startDateTime').text}, ignore_index=True)
这是我从这段代码中得到的:
index |name|serialNumber| startDateTime |znumber|
------|----|------------|------------------------|-------|
0016 |WSSA| 764000606 |2013-01-10T12:22:39.166Z| 03081 |
0017 |PSSF| 764000606 |2013-01-10T12:22:39.166Z| 02081 |
虽然我想要这个:看看 startDateTime
:
index |name|serialNumber| startDateTime |znumber|
------|----|------------|------------------------|-------|
0016 |WSSA| 764000606 |2014-01-10T12:22:39.166Z| 03081 |
0017 |PSSF| 764000606 |2013-01-10T12:22:39.166Z| 02081 |
有什么想法吗? 我正在使用 XML ElementTree
尝试以下操作,
import xml.dom.minidom as minidom
doc = minidom.parse('filename')
memoryElem = doc.getElementsByTagName('part')[0]
print memoryElem.getAttribute('number')
print memoryElem.getAttribute('name')
print memoryElem.getAttribute('index')
希望对你有所帮助
这是一个从 xml.
获取数据的示例code.py:
#!/usr/bin/env python3
import sys
import xml.etree.ElementTree as ET
from pprint import pprint as pp
file_name = "a.xml"
def get_product_sn(product_node):
for product_node_child in list(product_node):
if product_node_child.tag == "serialNumber":
return product_node_child.attrib.get("value", None)
return None
def get_parts_data(parts_node):
ret = list()
for parts_node_child in list(parts_node):
attrs = parts_node_child.attrib
ret.append({"number": attrs.get("number", None), "name": attrs.get("name", None), "index": attrs.get("index", None)})
return ret
def get_visit_node_data(visit_node):
ret = dict()
for visit_node_child in list(visit_node):
if visit_node_child.tag == "general":
for general_node_child in list(visit_node_child):
if general_node_child.tag == "startDateTime":
ret["startDateTime"] = general_node_child.text
elif general_node_child.tag == "endDateTime":
ret["endDateTime"] = general_node_child.text
elif visit_node_child.tag == "parts":
ret["parts"] = get_parts_data(visit_node_child)
return ret
def get_node_data(node):
ret = {"visits": list()}
for node_child in list(node):
if node_child.tag == "product":
ret["serialNumber"] = get_product_sn(node_child)
elif node_child.tag == "visits":
for visits_node_child in list(node_child):
ret["visits"].append(get_visit_node_data(visits_node_child))
return ret
def main():
tree = ET.parse(file_name)
root_node = tree.getroot()
data = get_node_data(root_node)
pp(data)
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
main()
备注:
- 它以树状方式处理 xml,因此它映射(如果您愿意)在 xml (如果xml结构发生变化,代码也要适配)
- 它被设计为通用的:get_node_data 可以在有 2 个子节点的节点上调用:product 和 访问次数。在我们的例子中,它是根节点本身,但在现实世界中,可能存在一系列这样的节点,每个节点都有我上面列出的 2 个子节点
- 它的设计易于出错,所以如果 xml 不完整,它会尽可能多地获取数据;我选择了这种(贪婪的)方法而不是遇到错误时它只是抛出异常的方法
- 因为我没有使用 pandas,而不是填充对象 我只是 return 一个 Python字典 (json);我认为将其转换为 DataFrame 应该不难
- 我 运行 它有 Python 2.7 和 Python 3.5
输出(包含 2 个键的字典)- 缩进以提高可读性:
- serialNumber - 序列号(很明显)
- visits(因为它是字典,所以我必须将此数据放在 "under" 键中)- 字典列表,每个字典都包含 访问节点
输出:
(py_064_03.05.04_test0) e:\Work\Dev\Whosebug\q045049761>"e:\Work\Dev\VEnvs\py_064_03.05.04_test0\Scripts\python.exe" code.py Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32 {'serialNumber': '764000606', 'visits': [{'endDateTime': '2014-03-11T13:51:31.480Z', 'parts': [{'index': '0016', 'name': 'WSSA', 'number': '03081'}], 'startDateTime': '2014-01-10T12:22:39.166Z'}, {'endDateTime': '2013-03-11T13:51:31.480Z', 'parts': [{'index': '0017', 'name': 'PSSF', 'number': '02081'}], 'startDateTime': '2013-01-10T12:22:39.166Z'}]}
@EDIT0:添加了多个 part 节点处理,如评论之一所述.该功能已移至 get_parts_data。现在,visits 列表中的每个条目都有一个 parts 键,其值将是一个列表,该列表由从每个 中提取的字典组成part节点(提供的xml不是这种情况)。