lib7 usage

This is a high level implementation for python3 of lib7. Source code of this implementation can be found here.

lib7 is a C implementation of an hl7 parser and composer. The parsing part has the goal of being resource and runtime efficient. The python3 implementation is an interface to this library for rapid prototyping and experimentation. This comes at a cost, runtime efficiency is not as good as with the C implementation (but it’s stil lfaster than a pure python implementation), however, writing code is much quicker.

You may use lib7.Message.__init__ or lib7.open_file() to create a lib7.Message Object for reading. see Reading HL7 Files.

lib7.compose() or lib7.Composer will create an object that let’s you manipulate a hl7 file. However, this method is slower and is, therefore, not optimal when parsing many files without the need of modifying the content. see Composing HL7 Files.

Understanding Addressing

You can either iterate trough all objects to find a node or you may use the get(addr) and set(addr, value) methods to get and set values. It is important to understand, that the HL7 structure actually has 6 hirarchy levels (most people forget FIELD repetitions ~ and SEGMENT repetitions, ie. multiple OBR segments).

MSH|...||||||||ORU&data^R01~rep1

MSH(1)-9(1).2.1 <--- all optional address values
 ^  ^  ^ ^  ^ ^
 |  |  | |  | +---- SUBCOMP
 |  |  | |  +------ COMPONENT
 |  |  | +--------- FIELD (optional? FIXME set default to 1)
 |  |  +----------- FIELDLIST
 |  +-------------- SEGMENT repetition (optional, defaults to 1)
 +----------------- SEGMENT

MSH                                SEGMENT
   |   ||||||||                    FIELDLIST
    ...                    ~rep1   FIELD
               ORU     ^R01        COMPONENT
                  &data            SUBCMP

Addressing in HL7 (as it is used) is often ambigous. The 2 cases where tis is true is by addressing SEGMENTs and FIELDs.

As an example:

REP|0|f1~rep1|f2
REP|1|f21|f2~rep2

Here we see the 2 repetitions:

  • a segment can occour multiple times in a hl7 message (typically OBR) or in this case REP

  • a field (typically delimited by | can have multiple repetitions delimited by ~

Often the value f1 is address by REP-2 but this would return f1~rep1 from the first line and f21 from the 2nd line. The correct addres to find f1 would be:

REP(1)-2(1)

or to find f21

REP(2)-2(1)

Reading HL7 Files

import lib7

msg = lib7.open("path/to/some/file.hl7")

# check what sort of message type this is, defined in MsH-9.1
msh91 = None
msh92 = None
try:
    msh91 = msg.get("MSH-9.1")
    print(msh91) # should print the content of the FIELD
except Hl7StructureException:
    print("MSH-9.1 Not found)

try:
    msh92 = msh91.next_sibling
except Hl7StructureException:
    print("MSH-9.2 Not found)

root = msh92
while root.parent:
    root = root.parent

# we have now found the top most node which is of type MESSAGE
# This node contains N segments in children
print(root.type) # prints: Type.MESSAGE
print("%r" % root) # prints: <MESSAGE (children: 2)>
print(root.num_children) # prints: 2
assert(root == msg) # same same but different (variable name)

# every node in the structure is an iterator which will
# iterate over all child nodes.
#
# This is the preferred way, because it is faster than first
# fetching all nodes via `n.children` and then looping over them.
for seg in root:
    print("%r" % seg)
    # prints: <SEGMENT MSH(1) (children: 18), MSH>
    #         <SEGMENT PID(1) (children: 1), PID>

    print(seg.addr)
    # prints: MSH(1)
    #         PID(1)

# or you may fetch a list of child ndoes like this:
children = root.children

# print the segment names
for c in children:
    print(c.data) # prints: MSH, PID, ...

See also:

Composing HL7 Files

With lib7.Composer you get access to writing and creating hl7 files. because lib7.Composer derives from lib7.Message, all the above methods described in Reading HL7 Files are applicable.

import lib7

# open an existing file for modifying
msg = lib7.compose("path/to/some/file.hl7")

# will create segment: "XYZ|^&mydata\r"
msg.set("XYZ(1)-1.2.3, "mydata")

# now write the changed data
msg.write_file("path/to/some/other.hl7")

# if you do bulk editing over many files, it is a good
# idea to free memory like so:
del(msg)

# create an empty message.
msg = lib7.compose()

# this message will already contain an MSH segment, always,
# it's really needed
#
# now you can start adding stuff
msg.set("PID-3(1), "patientnumber")

del(msg)

See also: