crs4 / hl7apy

Python library to parse, create and handle HL7 v2 messages.
http://crs4.github.io/hl7apy/
MIT License
231 stars 91 forks source link

Improve Documentation on How to Use Fields #8

Closed cancan101 closed 9 years ago

cancan101 commented 10 years ago

For example how are the constants in: https://github.com/crs4/hl7apy/blob/781dea7c5eb37256b7a4151b39ff3e45910cf39a/hl7apy/v2_2/fields.py#L22 used?

svituz commented 10 years ago

Actually, the versions modules (i.e. v2_2, v2_3, v2_4 ecc.) are not meant to be used directly. They contain references used by the core classes. For example, if you need to instantiate the Field PID_1 of the HL7 version 2.2, you're supposed to do this:

from hl7apy.core import Field
Field('PID_5', version="2.2")

And not something like:

from hl7apy.v2_2.fields import FIELDS
....

The Field class is in charge of the lookup of the PID_5 description in the v2_2 module. It is the same for the orher elements, for example:

Segment('PID')
Component('CX_10')

You can find other usage examples in the tutorial

cancan101 commented 10 years ago

The usage example that I could not find in the examples is around parsing. If I parsed a message using:

message = parse_message(msg_str)

and now have:

message.children[1].children[1].children[4].value
>>> 'OBX|3|ST|||Patient Name: ALEX TEST||||||P'

how do I programmatically access the OBSERVATION_VALUE value in that segment?

cancan101 commented 10 years ago

Okay. It looks like in this case the answer was:

message.children[1].children[1].children[4].children[0].observation_value
>>> [<Field OBX_5 (OBSERVATION_VALUE) of type varies>]

I would say more documentation would be helpful in understanding Groups (aka HL7 segment group) vs Segments and the fact you can read fields using attribute accesses.

svituz commented 10 years ago

In this case too it is not the expected method to use the API. The library is written in a way that you can navigate the elements (Message, Segments, Fields, etc) using their names. You should not access to the children attribute. In your case you can navigate the message to get the OBSERVATION_VALUE (OBX_5) field in this way

message.OBX.OBSERVATION_VALUE

or equivalently

message.OBX.OBX_5

I'd suggest to look the Getting Started page where these doubts should be clarified.

cancan101 commented 10 years ago

What is the correct way to do the following:

[x.OBX for x in message.ORU_R01_RESPONSE.ORU_R01_ORDER_OBSERVATION.ORU_R01_OBSERVATION]

If I write this:

message.ORU_R01_RESPONSE.ORU_R01_ORDER_OBSERVATION.ORU_R01_OBSERVATION.OBX

I get only the first Segment.

svituz commented 10 years ago

When accessing a named element the library return the first item of that kind of element. In other words, writing message.OBX is the same as writing message.OBX[0]. If you want another index you must specify it mesage.OBX[1]. This is done because it is common to have only one occurrence of a group, segment, field, ecc. (e.g. you can write m.msh.msh_9 instead of m.msh[0].msh_9[0]). It is different with iterations. In this case if you write for m.OBX you iterate all the OBX children of m. In your case, if you want all the OBX segments of a message, the correct code is:

[obx for obx in message.ORU_R01_RESPONSE.ORU_R01_ORDER_OBSERVATION.ORU_R01_OBSERVATION.OBX]

EDIT: this code creates the list of all the OBX segments of the first ORU_R01_OBSERVATION group not of the whole message

cancan101 commented 10 years ago

@svituz That does not work:

len([obx for obx in message.ORU_R01_RESPONSE.ORU_R01_ORDER_OBSERVATION.ORU_R01_OBSERVATION.OBX])
>> 1

whereas:

len([x.OBX for x in message.ORU_R01_RESPONSE.ORU_R01_ORDER_OBSERVATION.ORU_R01_OBSERVATION])
>> 33
svituz commented 10 years ago

Yes, sorry you're right. I was imprecise before: if you write m.OBX it returns the list of OBX segments in m. If you write m.OBX.OBX_1, it is the same as m.OBX[0].OBX_1. Sorry about that. That said, about the two operations you wrote they are two different operations:

cancan101 commented 10 years ago

I guess my question is how to get all of the OBX segments in:

message.ORU_R01_RESPONSE.ORU_R01_ORDER_OBSERVATION.ORU_R01_OBSERVATION
svituz commented 10 years ago

Then, you need to iterate all the groups.

for resp in message.ORU_R01_RESPONSE:
  for observ in resp.ORU_R01_ORDER_OBSERVATION:
      ...

Since this is a "deep" message you can use the parser option find_groups=False, which doesn't create the groups and inserts the OBX segments as direct children of the message. So it becomes

message = parse_message(msg_str, find_groups=False)
for obx in message.OBX:
    ...

It is important to note that in this case you're not using STRICT validation

cancan101 commented 10 years ago

I don't want all OBX in the entire message, just the OBXs that are currently returned by:

[x.OBX for x in message.ORU_R01_RESPONSE.ORU_R01_ORDER_OBSERVATION.ORU_R01_OBSERVATION]
svituz commented 10 years ago

You get all the OBXs in

message.ORU_R01_RESPONSE.ORU_R01_ORDER_OBSERVATION.ORU_R01_OBSERVATION

by writing

message.ORU_R01_RESPONSE.ORU_R01_ORDER_OBSERVATION.ORU_R01_OBSERVATION.OBX
cancan101 commented 10 years ago

But you wrote above that:

When accessing a named element the library return the first item of that kind of element. In other words, writing message.OBX is the same as writing message.OBX[0]

Which is consistent with my getting an iterable of only one item when I write that.

svituz commented 10 years ago

But then I wrote:

Yes, sorry you're right. I was imprecise before: if you write m.OBX it returns the list of OBX segments in m. If you write m.OBX.OBX_1, it is the same as m.OBX[0].OBX_1

cancan101 commented 10 years ago

Right, but I think that you were right there. I am only getting the first element.

svituz commented 10 years ago

It means that the group has only one OBX

rashmitpankhania commented 6 years ago

can you explain how to add multiple obx in message in ORU_R01 with group name ORU_R01_PATIENT_RESULT