python解析HL7协议多方式对比

说明

由于本文是从jupyter里直接导出的md文件,阅读效果不佳,请点击下面连接:

jupyter 预览效果

对比几种解析库:

  • python-hl7 很不友好,索引全部使用下标,不容易理解

  • hl7-parser:比较好用,所有字段都可以用英文含义索引,可以修改数据。不能直接获取含有数据的字段,需要遍历

  • HL7py:跟前者相似,可以通过英文含义索引,👍能以字典的方式返回所有数据的字段。 支持重新组装、构建hl7数据包。
    兼容性差,容易解析失败。而且需要做 2to3 转换。时间字段解析结果可能跟预想不一样。

本人对HL7协议并没有深入研究过,也不了解每个字段的含义,仅仅是为了满足工作需求,将自己对 解析工具的使用过程展现给大家,如有描述错误,不必太过计较。😜😜

HL7协议测试数据

message = 'MSH|^~\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\r'
message += 'PID|||555-44-4444||EVERYWOMAN^EVE^E^^^^L|JONES|196203520|F|||153 FERNWOOD DR.^^STATESVILLE^OH^35292||(206)3345232|(206)752-121||||AC555444444||67-A4335^OH^20030520\r'
message += 'PV1||I|W^389^1^UABH^^^^3||||12345^MORGAN^REX^J^^^MD^0010^UAMC^L||67890^GRAINGER^LUCY^X^^^MD^0010^UAMC^L|MED|||||A0||13579^POTTER^SHERMAN^T^^^MD^0010^UAMC^L|||||||||||||||||||||||||||200605290900'
message += 'OBR|1|845439^GHH OE|1045813^GHH LAB|1554-5^GLUCOSE|||200202150730||||||||555-55-5555^PRIMARY^PATRICIA P^^^^MD^^LEVEL SEVEN HEALTHCARE, INC.|||||||||F||||||444-44-4444^HIPPOCRATES^HOWARD H^^^^MD\r'
message += 'OBX|1|SN|1554-5^GLUCOSE^POST 12H CFST:MCNC:PT:SER/PLAS:QN||^182|mg/dl|70_105|H|||F'
message +=  'OBX||NM|AG_FiO2||21.00|%|18.00-100.00||||\r'
message = 'MSH|^~\&|||||20080521104435||ORU^R01|||2.3.1\r'\
            'PID||001|001||zhang^san||20091010|M\r' \
            'PV1||U|^^Bed1|||||||||||||||adult||||||||||||||||||||||||||20091111\r'\
            'OBR|||||||20170426111902\r' \
            'OBX||NM|HR||80|bmp |60-100\r'\
            'OBX||NM|AG_FiCO2||0.10|%|0.00-0.50||||\r'\
            'OBX||NM|AG_EtO2||19.00|%|0.00-100.00||||\r'\
            'OBX||NM|AG_FiO2||21.00|%|18.00-100.00||||\r'

python-hl7

这个。。。真不好使

pip install -U hl7

基本用法

import hl7

h = hl7.parse(message)
# 按下标获取一个段
h[1]
[['PID'],
 [''],
 ['001'],
 ['001'],
 [''],
 [[['zhang'], ['san']]],
 [''],
 ['20091010'],
 ['M']]
# 索引方式 vs 调用
h[1][2][0] == h(2)(3)(1)
True
# 以下几种索引方式效果一样
h[1] == h['PID'][0],  h['PID'] == h.segments('PID'), h['PID'][0] == h.segment('PID')
(True, True, True)
# 转为字符串
str(h[1][5])
'zhang^san'
# 索引到具体值
h[1][2][0]
'001'

hl7-parser(推荐)

pip install hl7parser

基本用法

message = 'MSH|^~\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\r'
message += 'EVN||200605290901||||200605290900\r'
message += 'PID|||555-44-4444||EVERYWOMAN^EVE^E^^^^L|JONES|196203520|F|||153 FERNWOOD DR.^^STATESVILLE^OH^35292||(206)3345232|(206)752-121||||AC555444444||67-A4335^OH^20030520\r'
message += 'PV1||U|^^Bed1|||||||||||||||adult||||||||||||||||||||||||||20091111\r'
message += 'OBR|1|845439^GHH OE|1045813^GHH LAB|1554-5^GLUCOSE|||200202150730||||||||555-55-5555^PRIMARY^PATRICIA P^^^^MD^^LEVEL SEVEN HEALTHCARE, INC.|||||||||F||||||444-44-4444^HIPPOCRATES^HOWARD H^^^^MD\r'
message += 'OBX|1|SN|1554-5^GLUCOSE^POST 12H CFST:MCNC:PT:SER/PLAS:QN||^182|mg/dl|70_105|H|||F\r'
message += 'OBX|2|NM|^Body Weight||79|kg^Kilogram^ISO+|||||F'
import hl7parser
from hl7parser.hl7 import HL7Message
msg = HL7Message(message)
msg
<hl7parser.hl7.HL7Message at 0x1679a42feb8>
str(msg.delimiters)
'|^~\\&'
str(msg.type)
'CNTRL-3456'
str(msg.header)
'MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4|'
str(msg.msh.version_id)
'2.4'
msg.message
'MSH|^~\\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\rEVN||200605290901||||200605290900\rPID|||555-44-4444||EVERYWOMAN^EVE^E^^^^L|JONES|196203520|F|||153 FERNWOOD DR.^^STATESVILLE^OH^35292||(206)3345232|(206)752-121||||AC555444444||67-A4335^OH^20030520\rPV1||U|^^Bed1|||||||||||||||adult||||||||||||||||||||||||||20091111\rOBR|1|845439^GHH OE|1045813^GHH LAB|1554-5^GLUCOSE|||200202150730||||||||555-55-5555^PRIMARY^PATRICIA P^^^^MD^^LEVEL SEVEN HEALTHCARE, INC.|||||||||F||||||444-44-4444^HIPPOCRATES^HOWARD H^^^^MD\rOBX|1|SN|1554-5^GLUCOSE^POST 12H CFST:MCNC:PT:SER/PLAS:QN||^182|mg/dl|70_105|H|||F\rOBX|2|NM|^Body Weight||79|kg^Kilogram^ISO+|||||F'
# 数据段信息
str(msg.segment_position)
"{'msh': 0, 'evn': 1, 'pid': 2, 'pv1': 3, 'obr': 4, 'obx': [5, 6]}"
# 所有 数据段 对象列表,用来迭代
msg.segments
[('msh', <hl7parser.hl7.HL7Segment at 0x1679a42f978>),
 ('evn', <hl7parser.hl7.HL7Segment at 0x1679bdd7ef0>),
 ('pid', <hl7parser.hl7.HL7Segment at 0x1679bdf3dd8>),
 ('pv1', <hl7parser.hl7.HL7Segment at 0x1679be02588>),
 ('obr', <hl7parser.hl7.HL7Segment at 0x1679be05278>),
 ('obx', <hl7parser.hl7.HL7Segment at 0x1679be24908>),
 ('obx', <hl7parser.hl7.HL7Segment at 0x1679be276a0>)]
# 通过下标位置索引
print(str(msg.pv1[17]), str(msg.pv1[43]))
print(str(msg.msh[10]))
adult 20091111
2.4
# 也可以修改
msg.pv1[17] = '123'
print(msg.pv1)
PV1||U|^^Bed1|||||||||||||||123||||||||||||||||||||||||||20091111|
# 通过属性(英文含义)索引
print(str(msg.msh.version_id))
print(str(msg.pid.patient_name))
print(str(msg.pv1.assigned_patient_location))
print(str(msg.obr.observation_datetime))
2.4
EVERYWOMAN^EVE^E^^^^L
^^Bed1
200202150730
# repeating fields
print(msg.pid.patient_name)
print(str(msg.pid.patient_name[0][1]))
EVERYWOMAN^EVE^E^^^^L
EVE
# 查看数据段的简略信息 { xxx属性: index }
# msg.msh.named_fields
# msg.pv1.named_fields
msg.obr.named_fields
{'set_id': 0,
 'placer_order_number': 1,
 'filler_order_number': 2,
 'universal_service_identifier': 3,
 'priority': 4,
 'requested_datetime': 5,
 'observation_datetime': 6}
# 查看某个数据段的详细字段属性,以及是否为必须字段、是否允许重复、其数据类型等等
msg.obr.field_definitions
# msg.msh.field_definitions   # MSH
# msg.pid.field_definitions   # PID
# msg.pv1.field_definitions   # PV1
# msg.obr.field_definitions   # OBR
# msg.obx[0].field_definitions   # 存在多个OBX时
[('set_id',
  {'required': False,
   'repeats': False,
   'type': hl7parser.hl7_data_types.HL7DataType,
   'index': None}),
 ('placer_order_number',
  {'required': False,
   'repeats': False,
   'type': hl7parser.hl7_data_types.HL7DataType,
   'index': None}),
 ('filler_order_number',
  {'required': False,
   'repeats': False,
   'type': hl7parser.hl7_data_types.HL7DataType,
   'index': None}),
 ('universal_service_identifier',
  {'required': False,
   'repeats': False,
   'type': hl7parser.hl7_data_types.HL7DataType,
   'index': None}),
 ('priority',
  {'required': False,
   'repeats': False,
   'type': hl7parser.hl7_data_types.HL7DataType,
   'index': None}),
 ('requested_datetime',
  {'required': False,
   'repeats': False,
   'type': hl7parser.hl7_data_types.HL7DataType,
   'index': None}),
 ('observation_datetime',
  {'required': False,
   'repeats': False,
   'type': hl7parser.hl7_data_types.HL7Datetime,
   'index': None})]
# by name or index
msg.evn[1] == msg.evn.recorded_datetime
True
# 部分 字段属性可能有子属性,可通过 field_map 继续查看详细
msg.msh.message_type.field_map
# hl7parser.hl7_data_types.HL7_PersonLocation.field_map
[('message_code',
  {'required': True,
   'repeats': False,
   'type': hl7parser.hl7_data_types.HL7DataType,
   'index': None}),
 ('trigger_event',
  {'required': True,
   'repeats': False,
   'type': hl7parser.hl7_data_types.HL7DataType,
   'index': None}),
 ('message_structure',
  {'required': True,
   'repeats': False,
   'type': hl7parser.hl7_data_types.HL7DataType,
   'index': None})]
# 举例
print(str(msg.msh.message_type),'-', str(msg.msh.message_type.message_code), '-', str(msg.msh.message_type.trigger_event))
ORU^R01 - ORU - R01
print(str(msg.msh[7]),'-', str(msg.msh.message_type[0]), '-', str(msg.msh.message_type[1]))
ORU^R01 - ORU - R01
# 查看数据类型
msg.evn.recorded_datetime.__class__
hl7parser.hl7_data_types.HL7Datetime
# 查看该数据类型支持的方法
list(filter(lambda x: not x.startswith('__'), dir(msg.evn.recorded_datetime)))
['component_map',
 'datetime',
 'field_map',
 'isNull',
 'isoformat',
 'precision',
 'set_attributes']
# 举例
print(msg.evn.recorded_datetime.isoformat())
2006-05-29T09:01:00
# repeating fields
type(msg.pid.patient_name[0])
hl7parser.hl7_data_types.HL7_ExtendedPersonName

HL7py

下载源码包,解压,然后用以下命令 , 将 py2文件转换成py3 文件,再安装

2to3 -w HL7py
python3 setup.py install

基本用法

from HL7py import parser
message = 'MSH|^~\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4\r'
message += 'PID|||555-44-4444||EVERYWOMAN^EVE^E^^^^L|JONES|196203520|F|||153 FERNWOOD DR.^^STATESVILLE^OH^35292||(206)3345232|(206)752-121||||AC555444444||67-A4335^OH^20030520\r'
message += 'PV1||I|W^389^1^UABH^^^^3||||12345^MORGAN^REX^J^^^MD^0010^UAMC^L||67890^GRAINGER^LUCY^X^^^MD^0010^UAMC^L|MED|||||A0||13579^POTTER^SHERMAN^T^^^MD^0010^UAMC^L|||||||||||||||||||||||||||200605290900'
message += 'OBR|1|845439^GHH OE|1045813^GHH LAB|1554-5^GLUCOSE|||200202150730||||||||555-55-5555^PRIMARY^PATRICIA P^^^^MD^^LEVEL SEVEN HEALTHCARE, INC.|||||||||F||||||444-44-4444^HIPPOCRATES^HOWARD H^^^^MD\r'
message += 'OBX|1|SN|1554-5^GLUCOSE^POST 12H CFST:MCNC:PT:SER/PLAS:QN||^182|mg/dl|70_105|H|||F'
msg = parser.parse(message, custom_levels={'OBR':1,'OBX':2})
msg
<HL7py.parser.Message at 0x1679be3bd30>
type(msg.MSH)
HL7py.parser.Segment
# 获取数据段名
msg.MSH.code
'MSH'
# hl7属性: 获取该节点的字符串(注意: 此处容易翻车😂)
print(msg.MSH.hl7)
print(msg.MSH.version.hl7)
MSH|^~\&|GHH LAB|ELAB-3|GHH OE|BLDG4|200202150930||ORU^R01|CNTRL-3456|P|2.4|||||||
2.4
# data属性:一键获取所有数据段,返回一个嵌套字典

msg.MSH.data
# msg.PID.data
# msg.EVN.data
# msg.IN1.data
{'code': 'MSH',
 'encoding_chars': '^~\\&',
 'send_app': {'app_name': 'GHH LAB'},
 'send_fac': 'ELAB-3',
 'recv_app': {'app_name': 'GHH OE'},
 'recv_fac': 'BLDG4',
 'timestamp': datetime.datetime(2002, 2, 15, 9, 30),
 'security': '',
 'msg_type': {'message_code': 'ORU', 'event_code': 'R01'},
 'msg_ctl_id': 'CNTRL-3456',
 'proc_id': 'P',
 'version': '2.4',
 'seq_no': '',
 'cont_pointer': '',
 'accept_ack_type': '',
 'application_ack_type': '',
 'country_code': '',
 'character_set': '',
 'principal_lang_of_msg': ''}
msg.PID.pat_address.data
{'street': '153 FERNWOOD DR.',
 'street2': '',
 'city': 'STATESVILLE',
 'state': 'OH',
 'zip': '35292',
 'country': '',
 'addr_type': '',
 'other': '',
 'other2': ''}
# data: 若没有子节点直接返回数据
print(msg.PID.pat_address.city.data)
print(msg.PV1.admit_dt_tm.data)
STATESVILLE
200605290900OBR
# 节点树状图
msg.PV1.fmt_tree()
 PV1
     OBX
# 如果有子节点(OBX 节点)
obx = msg.PV1.child_segments[0]
print(obx.hl7)
OBX|1|SN|1554-5^GLUCOSE^POST 12H CFST:MCNC:PT:SER/PLAS:QN||^182|mg/dl|70_105|H|||F||||
# 构建一个完整 hl7 数据包
from HL7py.parser import Message, Segment
import datetime
msg = Message()

msh_data = dict(recv_app={'app_name': 'Their App'},
                send_app={'app_name': 'ANKHOS'},
                msg_type=dict(message_code='ADT', event_code='A08'),
                accept_ack_type='AL',
                application_ack_type='AL',
                proc_id='P',
                version='2.3',
                encoding_chars='^~\&',
                timestamp=datetime.datetime.now())
MSH = Segment(code='MSH', data=msh_data)
evn_data = dict(event_code='R01',
                timestamp=dict(time=datetime.datetime.now(), resolution='S'))
EVN = Segment(code='EVN', data=evn_data)
PID = Segment(code='PID', data={})
pv1_data = {}
PV1 = Segment(code='PV1', data=pv1_data)
msg.add_segments([MSH, EVN, PID, PV1])

#Voila!
print(msg.hl7)
PV1|||^^^^^^^^||||^^^^^^^^^&&^&&^|^^^^^^^^^&&^&&^||||||||||||||||||||||||||||||||||||||||||||
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值