我正在尝试从XML提取某些数据点,并尝试了两种选择...
这是我到目前为止所得到的,
代码
# Packages
# --------------------------------------
import xml.etree.ElementTree as ET
# XML Data
# --------------------------------------
message_xml = \
'<ClinicalDocument> \
<code code="34133-9" displayName="Summarization of Episode Note"/> \
<title>Care Summary</title> \
<recordTarget> \
<patientRole> \
<id assigningAuthorityName="LOCAL" extension="L123456"/> \
<id assigningAuthorityName="SSN" extension="788889999"/> \
<id assigningAuthorityName="GLOBAL" extension="G123456"/> \
<addr use="HP"> \
<streetAddressLine>1000 N SOME AVENUE</streetAddressLine> \
<city>BIG CITY</city> \
<state>NA</state> \
<postalCode>12345-1010</postalCode> \
<country>US</country> \
</addr> \
<telecom nullFlavor="NI"/> \
<patient> \
<name use="L"> \
<given>JANE</given> \
<given>JOE</given> \
<family>DOE</family> \
</name> \
</patient> \
</patientRole> \
</recordTarget> \
</ClinicalDocument>'
# Get Tree & Root
# --------------------------------------
tree = ET.ElementTree(ET.fromstring(message_xml))
root = tree.getroot()
# Iterate
# --------------------------------------
for node in root:
tag = node.tag
attribute = node.attrib
# Get ClinicalDocument.code values
if tag == 'code':
document_code_code = attribute.get('code')
document_code_name = attribute.get('displayName')
else:
pass
# Get ClinicalDocument.recordTarget values
if tag == 'recordTarget':
for child in node.iter():
# Multiple <id> tags
record_target_local = ??
record_target_ssn = ??
record_target_global = ??
# Multiple <given> tags
record_target_name_first = ??
record_target_name_middle = ??
record_target_name_last = ??
else:
pass
预期产量
document_code,document_name,id_local,id_ssn,id_global,name_first, name_middle,name_last
34133-9,Summarization of Episode Note,L123456,788889999,G123456,JANE,JOE,DOE
可接受的输出
document_code,document_name,id_type,id,name_first,name_middle,name_last
34133-9,Summarization of Episode Note,LOCAL,L123456,JANE,JOE,DOE
34133-9,Summarization of Episode Note,SSN,788889999,JANE,JOE,DOE
34133-9,Summarization of Episode Note,GLOBAL,G123456,JANE,JOE,DOE
问题
<id>
,<given>
)?答案 0 :(得分:1)
如何有效地导航具有多个子节点的子节点 在他们之下?
使用XPath是浏览XML的一种好方法。 ElementTree具有limited XPath support,但看起来足以满足您的需求。如果最终需要使用更复杂的XPath,建议您使用XPath in lxml。
如何处理重复的标签(例如:
<id>
,<given>
)?
这取决于您需要对这些元素执行什么操作。例如,如果要为每个id
元素分配单独的行,则需要对每个元素进行迭代(在ElementTree中使用findall()
或在lxml中使用xpath()
)。
如果只需要一个值(文本值或属性值),则需要将其范围缩小到XPath中的单个元素。
例如,一个id
属性值等于assigningAuthorityName
的{{1}}元素将是LOCAL
。
id[@assigningAuthorityName='LOCAL']
元素有点棘手;您如何分辨一个是名字,另一个是中间名?我唯一能看到的就是位置。第一个given
(given
)是名字,第二个given[1]
(given
)是名字。您是否保证总是有两个given[2]
元素?如果没有,则可能需要进行一些检查或try / except语句以获取所需的输出。
此外,由于您正在创建csv输出,因此建议您使用csv module;特别是DictWriter。
这将允许您将XML中的值存储在字典中以写入行。您可以为新行创建字典的新副本,同时保持公用值(例如given
和document_code
)。
下面是一个示例,该示例将为每个document_name
创建一个新行。
XML输入(input.xml)
recordTarget
Python
<ClinicalDocument>
<code code="34133-9" displayName="Summarization of Episode Note"/>
<title>Care Summary</title>
<recordTarget>
<patientRole>
<id assigningAuthorityName="LOCAL" extension="L123456"/>
<id assigningAuthorityName="SSN" extension="788889999"/>
<id assigningAuthorityName="GLOBAL" extension="G123456"/>
<addr use="HP">
<streetAddressLine>1000 N SOME AVENUE</streetAddressLine>
<city>BIG CITY</city>
<state>NA</state>
<postalCode>12345-1010</postalCode>
<country>US</country>
</addr>
<telecom nullFlavor="NI"/>
<patient>
<name use="L">
<given>JANE</given>
<given>JOE</given>
<family>DOE</family>
</name>
</patient>
</patientRole>
</recordTarget>
</ClinicalDocument>
CSV输出(output.csv)
import csv
import xml.etree.ElementTree as ET
from copy import deepcopy
values_template = {"document_code": "", "document_name": "", "id_local": "", "id_ssn": "",
"id_global": "", "name_first": "", "name_middle": "", "name_last": ""}
with open("output.csv", "w", newline="") as csvfile:
csvwriter = csv.DictWriter(csvfile, delimiter=",", quoting=csv.QUOTE_MINIMAL,
fieldnames=[name for name in values_template])
csvwriter.writeheader()
tree = ET.parse('input.xml')
values_template["document_code"] = tree.find("code").get("code")
values_template["document_name"] = tree.find("code").get("displayName")
for target in tree.findall("recordTarget"):
values = deepcopy(values_template)
values["id_local"] = target.find("patientRole/id[@assigningAuthorityName='LOCAL']").get("extension")
values["id_ssn"] = target.find("patientRole/id[@assigningAuthorityName='SSN']").get("extension")
values["id_global"] = target.find("patientRole/id[@assigningAuthorityName='GLOBAL']").get("extension")
values["name_first"] = target.find("patientRole/patient/name/given[1]").text
values["name_middle"] = target.find("patientRole/patient/name/given[2]").text
values["name_last"] = target.find("patientRole/patient/name/family").text
csvwriter.writerow(values)
这是另一个示例,它将为每个recordTarget / patientRole / id ...创建一个新行。
Python
document_code,document_name,id_local,id_ssn,id_global,name_first,name_middle,name_last
34133-9,Summarization of Episode Note,L123456,788889999,G123456,JANE,JOE,DOE
CSV输出(output.csv)
import csv
import xml.etree.ElementTree as ET
from copy import deepcopy
values_template = {"document_code": "", "document_name": "", "id": "",
"name_first": "", "name_middle": "", "name_last": ""}
with open("output.csv", "w", newline="") as csvfile:
csvwriter = csv.DictWriter(csvfile, delimiter=",", quoting=csv.QUOTE_MINIMAL,
fieldnames=[name for name in values_template])
csvwriter.writeheader()
tree = ET.parse('input.xml')
values_template["document_code"] = tree.find("code").get("code")
values_template["document_name"] = tree.find("code").get("displayName")
for target in tree.findall("recordTarget"):
values = deepcopy(values_template)
values["name_first"] = target.find("patientRole/patient/name/given[1]").text
values["name_middle"] = target.find("patientRole/patient/name/given[2]").text
values["name_last"] = target.find("patientRole/patient/name/family").text
for role_id in target.findall("patientRole/id"):
values["id"] = role_id.get("extension")
csvwriter.writerow(values)