How to correctly parse an HL7 message using python HL7Apy?

Question:

Here is my code:

from hl7apy.parser import parse_message

hl7 = open("hl7.txt", "r").read()
msg = parse_message(hl7)
print(msg.children)

result:

[<Segment MSH>]

It shows only the first segment, seems simple but I don’t know what i’m doing wrong.

I’ve tried from a text file, passing the message directly or even with another HL7 message, but always got same results.

Here is the message:

MSH|^~&|SendingAPP|TEST|||20080617143943||ORU^R01|1|P|2.3.1||||||UNICODE
PID|1||7393670^^^^MR||Joan^JIang||19900804000000|Female
PV1|1||nk^^001
OBR|1||20071207011|00001^Automated Count^99MRC||20080508140600|20080508150616|||John||||20080508150000||||||||||HM||||||||TEST

Here is my message in notepad++ where all characters are shown:
Message in notepad++

Asked By: infantry

||

Answers:

I think your issue is the the MLLP constant for HL7apy is a Carriage return r. If you replace the new line characters n the groups will parse out fine

from hl7apy.parser import parse_message
from hl7apy.core import Group, Segment

hl7 = """
MSH|^~&|SendingAPP|TEST|||20080617143943||ORU^R01|1|P|2.3.1||||||UNICODE
PID|1||7393670^^^^MR||Joan^JIang||19900804000000|Female PV1|1||nk^^001
OBR|1||20071207011|00001^Automated
Count^99MRC||20080508140600|20080508150616|||John||||20080508150000||||||||||HM||||||||TEST
"""

msg = parse_message(hl7.replace('n', 'r'), find_groups=True, validation_level=2)
print(msg.children)
print(msg.children[1].children)

for segment in msg.children:
    if isinstance(segment, Segment):
        for attribute in segment.children:
            print(attribute, attribute.value)
    if isinstance(segment, Group):
        for group in segment.children:
            for group_segment in group.children:
                for attribute in group_segment.children:
                    print(attribute, attribute.value)
Answered By: badger0053

Additionaly to the answer above you can use an exception handler

from hl7apy import parser
from hl7apy.core import Group, Segment
from hl7apy.exceptions import UnsupportedVersion

and use it like this

 try:
     msg = parser.parse_message(hl7)
 except UnsupportedVersion:
     msg = parser.parse_message(hl7.replace("n", "r"))

If your message is correct you can acces the contents of fields like this

 print(msg.ORU_R01_PATIENT_RESULT.ORU_R01_PATIENT.PID.PID_7.value)
 print(msg.ORU_R01_PATIENT_RESULT.ORU_R01_PATIENT.ORU_R01_VISIT.PV1.PV1_1.value)
 print(msg.ORU_R01_PATIENT_RESULT.ORU_R01_ORDER_OBSERVATION.OBR.OBR_3.value)

So an enhanced answer showing all groups and subgroups – but still not perfect – can be e.g.

from hl7apy import parser
from hl7apy.core import Group, Segment
from hl7apy.exceptions import UnsupportedVersion

hl7 = open("hl7.txt", "r").read()

try:
    msg = parser.parse_message(hl7.replace('n', 'r'), find_groups=True, validation_level=2)
except UnsupportedVersion:
    msg = parser.parse_message(hl7.replace('n', 'r'), find_groups=True, validation_level=2)

indent = "    "
indent_seg = "    "
indent_fld = "        "

def subgroup (group, indent):
    indent = indent + "    "
    print (indent , group)
    for group_segment in group.children:
        if isinstance(group_segment, Group):
            subgroup (group_segment)
        else: 
            print(indent_seg, indent ,group_segment)
            for attribute in group_segment.children:
                print(indent_fld, indent ,attribute, attribute.value)


def showmsg (msg):
    print(msg.children[1])
    for segment in msg.children:
        if isinstance(segment, Segment):
            print (indent ,segment)
            for attribute in segment.children:
                print(indent_fld, indent, attribute, attribute.value)
        if isinstance(segment, Group):
            for group in segment.children:
                print (indent,group)
                for group_segment in group.children:
                    if isinstance (group_segment, Group): 
                        subgroup (group_segment, indent)
                    else:
                        print(indent_seg, indent ,group_segment)
                        for attribute in group_segment.children:
                            print(indent_fld, indent, attribute, attribute.value)

showmsg (msg)     

can give a result like this

<Group ORU_R01_PATIENT_RESULT>
    <Segment MSH>
             <Field MSH_1 (FIELD_SEPARATOR) of type ST> |
             <Field MSH_2 (ENCODING_CHARACTERS) of type ST> ^~&
             <Field MSH_3 (SENDING_APPLICATION) of type HD> SendingAPP
             <Field MSH_4 (SENDING_FACILITY) of type HD> TEST
             <Field MSH_7 (DATE_TIME_OF_MESSAGE) of type TS> 20080617143943
             <Field MSH_9 (MESSAGE_TYPE) of type MSG> ORU^R01
             <Field MSH_10 (MESSAGE_CONTROL_ID) of type ST> 1
             <Field MSH_11 (PROCESSING_ID) of type PT> P
             <Field MSH_12 (VERSION_ID) of type VID> 2.3.1
             <Field MSH_18 (CHARACTER_SET) of type ID> UNICODE
    <Group ORU_R01_PATIENT>
         <Segment PID>
             <Field PID_1 (SET_ID_PID) of type SI> 1
             <Field PID_3 (PATIENT_IDENTIFIER_LIST) of type CX> 7393670^^^^MR
             <Field PID_5 (PATIENT_NAME) of type XPN> Joan^JIang
             <Field PID_7 (DATE_TIME_OF_BIRTH) of type TS> 19900804000000
             <Field PID_8 (SEX) of type IS> Female
        <Group ORU_R01_VISIT>
             <Segment PV1>
                 <Field PV1_1 (SET_ID_PV1) of type SI> 1
                 <Field PV1_3 (ASSIGNED_PATIENT_LOCATION) of type PL> nk^^001
    <Group ORU_R01_ORDER_OBSERVATION>
         <Segment OBR>
             <Field OBR_1 (SET_ID_OBR) of type SI> 1
             <Field OBR_3 (FILLER_ORDER_NUMBER) of type EI> 20071207011
             <Field OBR_4 (UNIVERSAL_SERVICE_ID) of type CE> 00001^Automated Count^99MRC
             <Field OBR_6 (REQUESTED_DATE_TIME) of type TS> 20080508140600
             <Field OBR_7 (OBSERVATION_DATE_TIME) of type TS> 20080508150616
             <Field OBR_10 (COLLECTOR_IDENTIFIER) of type XCN> John
             <Field OBR_14 (SPECIMEN_RECEIVED_DATE_TIME) of type TS> 20080508150000
             <Field OBR_24 (DIAGNOSTIC_SERV_SECT_ID) of type ID> HM
             <Field OBR_32 (PRINCIPAL_RESULT_INTERPRETER) of type NDL> TEST1
    <Group ORU_R01_ORDER_OBSERVATION>
         <Segment OBR>
             <Field OBR_1 (SET_ID_OBR) of type SI> 2
             <Field OBR_3 (FILLER_ORDER_NUMBER) of type EI> 20071207011
             <Field OBR_4 (UNIVERSAL_SERVICE_ID) of type CE> 00001^Automated Count^99MRC
             <Field OBR_6 (REQUESTED_DATE_TIME) of type TS> 20080508140600
             <Field OBR_7 (OBSERVATION_DATE_TIME) of type TS> 20080508150616
             <Field OBR_10 (COLLECTOR_IDENTIFIER) of type XCN> John
             <Field OBR_14 (SPECIMEN_RECEIVED_DATE_TIME) of type TS> 20080508150000
             <Field OBR_24 (DIAGNOSTIC_SERV_SECT_ID) of type ID> HM
             <Field OBR_32 (PRINCIPAL_RESULT_INTERPRETER) of type NDL> TEST2
        <Group ORU_R01_OBSERVATION>
             <Segment OBX>
                 <Field OBX_1 (SET_ID_OBX) of type SI> 1
                 <Field OBX_2 (VALUE_TYPE) of type ID> 2
Answered By: sqlab

by disabling find_groups like this msg = parser.parse_message(hl7, find_groups=False) My messages are now parsed correctly.

Thx to @sqlab and @badger0053 for help, i was able to make a progression.

Answered By: infantry
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.