python-xml-hl7

A library for parsing HL7 (version 2.x) messages in XML format into Python objects


Keywords
hl7, health, level, xml, python-hl7, python-xml-hl7
License
MIT
Install
pip install python-xml-hl7==1.3.0

Documentation

PyPi version Build Status codecov

python-xml-hl7

A library for parsing HL7 (version 2.x) messages in XML format into Python objects

Instalation

You can install this library using pip:

pip install python-xml-hl7

or from the git repository:

git clone https://github.com/weynelucas/python-xml-hl7.git
cd python-xml-hl7
python setup.py install

Quickstart

As an example, let’s create a HL7 message:

message = """
<ORU_R01>
<MSH><MSH.1>|</MSH.1><MSH.2>^~\\&amp;</MSH.2><MSH.3>hospital</MSH.3><MSH.7>20180703111743</MSH.7><MSH.9><MSH.9.1>ORU</MSH.9.1><MSH.9.2>R01</MSH.9.2></MSH.9><MSH.12>2.3.1</MSH.12></MSH>
<PID><PID.2>shenzhen</PID.2><PID.3>1</PID.3><PID.5>libang</PID.5><PID.7>20091010</PID.7><PID.8>M</PID.8></PID>
<PV1><PV1.2>U</PV1.2><PV1.18>adult</PV1.18><PV1.44>20180726181346</PV1.44></PV1>
<OBR><OBR.7>20180703111743</OBR.7></OBR>
<OBX><OBX.2>NM</OBX.2><OBX.3>SPO2</OBX.3><OBX.5>96</OBX.5><OBX.6>%</OBX.6><OBX.7>90-100</OBX.7></OBX>
<OBX><OBX.2>NM</OBX.2><OBX.3>PR</OBX.3><OBX.5>68</OBX.5><OBX.6>bpm</OBX.6><OBX.7>50-120</OBX.7></OBX>
<OBX><OBX.2>NM</OBX.2><OBX.3>SYS</OBX.3><OBX.5>131</OBX.5><OBX.6>mmHg</OBX.6><OBX.7>90-160</OBX.7><OBX.14>20180703111713</OBX.14></OBX>
<OBX><OBX.2>NM</OBX.2><OBX.3>DIA</OBX.3><OBX.5>85</OBX.5><OBX.6>mmHg</OBX.6><OBX.7>50-90</OBX.7><OBX.14>20180703111713</OBX.14></OBX>
<OBX><OBX.2>NM</OBX.2><OBX.3>MAP</OBX.3><OBX.5>100</OBX.5><OBX.6>mmHg</OBX.6><OBX.7>60-110</OBX.7><OBX.14>20180703111713</OBX.14></OBX>
<OBX><OBX.2>NM</OBX.2><OBX.3>NIBP_PR</OBX.3><OBX.5>73</OBX.5><OBX.6>bpm</OBX.6><OBX.7>50-120</OBX.7><OBX.14>20180703111713</OBX.14></OBX>
</ORU_R01>
"""

Call hl7.xml.parse() command to convert the string message

from hl7.xml import parse

h = parse(message)

This command returns a Message instance, wrapping a series of Segment objects. Is possible iterate over segments or match for specific ones:

>>> list(h) # List all message segments
[<hl7.xml.containers.MSH>,
 <hl7.xml.containers.PID>,
 <hl7.xml.containers.PV1>,
 <hl7.xml.containers.OBR>,
 <hl7.xml.containers.OBX: SPO2>,
 <hl7.xml.containers.OBX: PR>,
 <hl7.xml.containers.OBX: SYS>,
 <hl7.xml.containers.OBX: DIA>,
 <hl7.xml.containers.OBX: MAP>,
 <hl7.xml.containers.OBX: NIBP_PR>]

>>> h[0]  # Get 1st message segment
<hl7.xml.containers.MSH>

>>> h['OBX'] # Find all OBX segments
[<hl7.xml.containers.OBX: SPO2>,
 <hl7.xml.containers.OBX: PR>,
 <hl7.xml.containers.OBX: SYS>,
 <hl7.xml.containers.OBX: DIA>,
 <hl7.xml.containers.OBX: MAP>,
 <hl7.xml.containers.OBX: NIBP_PR>]

A Segment instance wraps a serie of Field objects, you can iterate over them:

>>> list(h[2]) # List all fields for 3rd message segment (PV1)
[<hl7.xml.containers.Field: PV1.2>,
 <hl7.xml.containers.Field: PV1.18>,
 <hl7.xml.containers.Field: PV1.44>]

>>> list(h[5]) # List all fields for 6th message segment (OBX)
[<hl7.xml.containers.Field: OBX.2>,
 <hl7.xml.containers.Field: OBX.3>,
 <hl7.xml.containers.Field: OBX.5>,
 <hl7.xml.containers.Field: OBX.6>,
 <hl7.xml.containers.Field: OBX.7>]

>>> h[5][0].value
'NM'

>>> h[5][2].value
'62'

There are different types of Segment, they are: MSH, PID, PV1, OBR and OBX. Each of them has helper methods to retrieve data from its respective HL7 segment without iterate over his Field objects

MSH

>>> msh = h['MSH'][0]
>>> (msh.field_separator,
     msh.encoding_chars,
     msh.sending_application,
     msh.datetime,
     msh.version,
     msh.message_type)
('|', '^~\\&', 'hospital', datetime.datetime(2018, 7, 3, 11, 17, 43), '2.3.1', ('ORU', 'R01'))

PID

>>> pid = h['PID'][0]
>>> (pid.id,
     pid.id_list,
     pid.name,
     pid.birthdate,
     pid.gender)
('shenzhen', '1', 'libang', datetime.datetime(2009, 10, 10, 0, 0), 'M')

PV1

>>> pv1 = h['PV1'][0]
>>> (pv1.patient_class,
     pv1.patient_class_display,
     pv1.patient_type,
     pv1.patient_type_display,
     pv1.assigned_patient_location,
     pv1.admit_datetime)
('U', 'Unknown', 'adult', 'Adult', None, datetime.datetime(2018, 7, 26, 18, 13, 46))

OBR

>>> obr = h['OBR'][0]
>>> obr.datetime
datetime.datetime(2018, 7, 3, 11, 17, 43)

OBX

>>> obx = h['OBX'][3] # 4th OBX instance
>>> (obx.identifier,
     obx.value_type,
     obx.value,
     obx.units,
     obx.reference_range,
     obx.datetime)
('DIA', 'NM', 85, 'mmHg', (50, 90), datetime.datetime(2018, 7, 3, 11, 17, 13))

To find a OBX segment or value inside a Message by its identifier, use get_obx and get_obx_value methods:

>>> h.get_obx('DIA')
<hl7.xml.containers.OBX: DIA>

>>> h.get_obx('DIA').value
85

>>> h.get_obx_value('SPO2')
96

Network client

python-xml-hl7 provides a simple network (TCP/IP) client, wich reads HL7 messages from Alfamed patient monitors like VITA 200e

from hl7.xml.client import AlfamedClient

client = AlfamedClient('169.254.215.35') # Default communication port is 9100
client.read_message()  # By default, HL7 messages are converted into Message objects
client.read_message(parse_message=False) # Returns the original HL7 message as string

AlfamedClient objects instantiated with invalid host addresses will raises AttributeError

Testing

You can run tests locally using unittest module

cd python-xml-hl7
python -m unittest tests

If all the tests pass you will see a success message like this:

.................
----------------------------------------------------------------------
Ran 17 tests in 0.007s

OK

Notes

  • Specification for XML encoding rules of HL7 v2 messages can be found here
  • For any suggestion, feature or bug fix, you can report an issue here. Or submit a pull request
  • For handle HL7 messages in original stream format, use solutions like python-hl7 or HL7apy

Release Notes

  • 1.0.0 - First release
  • 1.1.0 - Find OBX segments with get_obx and get_obx_value
  • 1.2.0 - String representation for client and container objects
  • 1.3.0 - Add Travis and Codecov support