HL7 (elixir_hl7 v0.10.0)
View SourceStruct and functions for parsing and manipulating HL7 messages.
This library specifically handles version 2.x of HL7 as it is by far the most prevalent format in production.
Check out HL7 on Wikipedia for a decent overview of the format.
Since HL7 messages often lack critical contextual metadata, this struct also contains a tags
field for metadata support.
Use new/2
or new!/2
to convert HL7 text to a parsed HL7 struct.
This struct supports the String.Chars
protocol such that to_string/1
can be used to format the HL7 message text.
To see the parsed representation, call get_segments/1
.
To query or update HL7 data, use the sigil_p/2
macro to provide an HL7.Path
with compile-time guarantees.
For dynamic path access, use HL7.Path.new/1
to construct paths on the fly.
Note that HL7 path formats have been designed to reflect common industry usage.
The get/2
, put/3
, and update/4
functions are designed to query and manipulate HL7 data as an HL7 struct (containing a message),
a list of segments, a single segment, a list of repetitions, or a single repetition. These should handle data as
nested lists (automatically converted to 1-indexed maps), nested sparse maps (1-indexed), simple strings, or mixes of each.
Use set_segments/2
to fully replace the content an HL7 message.
Migrating from HL7.Message, HL7.Segment and HL7.Query
To migrate from the deprecated HL7.Message
struct, use HL7.new!/2
and HL7.Message.new/2
to transform from one
struct to the other while preserving associated metadata tags.
You can use chunk_by_lead_segment/3
to generate segment groups to update code that relies on HL7.Query
groupings.
Any operations to otherwise query or modify HL7 data should be possible using
the get/2
, put/3
, update!/3
and update/4
functions.
If you encounter other issues with feature parity, please open an issue!
String.Chars Protocol
You can use the to_string()
implementation of the String.Chars
protocol to quickly render HL7 structs as text.
Summary
Functions
Creates a list of lists in which the specified segment_name
is used to get the first segment map
of each list. This function helps to do things like grouping OBX
segments with their parent OBR
segment.
Converts an HL7
struct into its string representation.
Convenience options will be added in the future.
Returns a list of sparse maps (with ordinal indices and strings) representing
the parsed segments of an HL7 message stored in an HL7
struct.
Returns a map of custom metadata associated with the HL7
struct.
Labels source data (a segment map or list of segment maps) by using HL7.Path
s in a labeled
output template.
Creates an HL7 struct from valid HL7 data (accepting text, lists or the deprecated HL7.Message
struct).
Returns {:ok, HL7.t()}
if successful, {:error, HL7.InvalidMessage.t()}
otherwise.
Creates an HL7 struct from valid HL7 data (accepting text, lists or the deprecated HL7.Message
struct).
Raises with a RuntimeError
if the data is not valid HL7.
Creates a minimal map representing an empty HL7 segment that can be modified via this module.
Opens an HL7 file stream of either :mllp
or :line
. If the file_type is not specified
it will be inferred from the first three characters of the file contents.
Sets a list of sparse maps (with ordinal indices and strings) representing
the parsed segments of an HL7 message to define the content of an HL7
struct.
Sets a map of custom metadata associated with the HL7
struct.
The ~p
sigil encodes an HL7 path into a struct at compile-time to guarantee correctness and speed.
It is designed to work with data returned by HL7.new!/1
, providing a standard way to get and update
HL7 message content.
Converts an HL7 message struct into a nested list of strings.
Updates data within an HL7
struct, parsed segments, or repetitions
using an HL7.Path
struct (see sigil_p/2
). Raises a RuntimeError
if the path is not present in the source data.
Types
@type file_type_hl7() :: :mllp | :line | nil
@type hl7_list_data() :: String.t() | [hl7_list_data()]
@type hl7_map_data() :: %{optional(non_neg_integer()) => hl7_map_data() | String.t()}
@type parsed_hl7() :: t() | segment() | [segment()] | hl7_map_data()
@type segment() :: %{ required(0) => String.t(), optional(pos_integer()) => hl7_map_data() | String.t() }
Functions
Creates a list of lists in which the specified segment_name
is used to get the first segment map
of each list. This function helps to do things like grouping OBX
segments with their parent OBR
segment.
Options:
keep_prefix_segments: true
will leave the first set of non-matching segments in the return value.
Converts an HL7
struct into its string representation.
Convenience options will be added in the future.
@spec get(parsed_hl7(), HL7.Path.t()) :: hl7_map_data() | [hl7_map_data()] | String.t() | nil
Finds data within an HL7
struct, parsed segments or repetitions
using an HL7.Path
struct (see sigil_p/2
).
Selecting data across multiple segments or repetitions with the wildcard [*]
pattern
will return a list of results.
Repetition data can be searched using a partial path containing ony the component and/or
subcomponent with a preceding period, e.g. ~p".2.3"
.
See the sigil_p/2
docs and tests for more examples!
Examples
iex> import HL7, only: :sigils
iex> HL7.Examples.wikipedia_sample_hl7()
...> |> HL7.new!()
...> |> HL7.get(~p"OBX-5")
"1.80"
iex> import HL7, only: :sigils
iex> HL7.Examples.wikipedia_sample_hl7()
...> |> HL7.new!()
...> |> HL7.get(~p"OBX[*]-5")
["1.80", "79"]
iex> import HL7, only: :sigils
iex> HL7.Examples.wikipedia_sample_hl7()
...> |> HL7.new!()
...> |> HL7.get(~p"OBX[*]-2!")
["N", "NM"]
iex> import HL7, only: :sigils
iex> HL7.Examples.wikipedia_sample_hl7()
...> |> HL7.new!()
...> |> HL7.get(~p"PID-11[*].5")
["35209", "35200"]
iex> import HL7, only: :sigils
iex> HL7.Examples.wikipedia_sample_hl7()
...> |> HL7.new!()
...> |> HL7.get(~p"PID-11[2].1")
"NICKELL’S PICKLES"
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7()
...> |> new!()
...> |> get(~p"PID")
...> |> get(~p"11[*]")
...> |> get(~p".1")
["260 GOODWIN CREST DRIVE", "NICKELL’S PICKLES"]
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7() |> new!() |> get(~p"OBX[*]")
[
%{
0 => "OBX",
1 => "1",
2 => %{1 => %{1 => "N", 2 => %{1 => "K", 2 => "M"}}},
3 => %{1 => %{2 => "Body Height"}},
5 => "1.80",
6 => %{1 => %{1 => "m", 2 => "Meter", 3 => "ISO+"}},
11 => "F"
},
%{
0 => "OBX",
1 => "2",
2 => "NM",
3 => %{1 => %{2 => "Body Weight"}},
5 => "79",
6 => %{1 => %{1 => "kg", 2 => "Kilogram", 3 => "ISO+"}},
11 => "F"
}
]
Returns a list of sparse maps (with ordinal indices and strings) representing
the parsed segments of an HL7 message stored in an HL7
struct.
Returns a map of custom metadata associated with the HL7
struct.
Labels source data (a segment map or list of segment maps) by using HL7.Path
s in a labeled
output template.
One-arity functions placed as output template values will be called with the source data.
Examples
iex> import HL7, only: :sigils
iex> HL7.Examples.wikipedia_sample_hl7()
...> |> HL7.new!()
...> |> HL7.label(%{mrn: ~p"PID-3!", name: ~p"PID-5.2"})
%{mrn: "56782445", name: "BARRY"}
@spec new(String.t(), Keyword.t()) :: {:ok, t()} | {:error, HL7.InvalidMessage.t()}
Creates an HL7 struct from valid HL7 data (accepting text, lists or the deprecated HL7.Message
struct).
Returns {:ok, HL7.t()}
if successful, {:error, HL7.InvalidMessage.t()}
otherwise.
@spec new!(list() | String.t() | HL7.Message.t(), Keyword.t()) :: t()
Creates an HL7 struct from valid HL7 data (accepting text, lists or the deprecated HL7.Message
struct).
Raises with a RuntimeError
if the data is not valid HL7.
Examples
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7() |> new!()
#HL7<with 8 segments>
Creates a minimal map representing an empty HL7 segment that can be modified via this module.
@spec open_hl7_file_stream(String.t(), file_type_hl7()) :: Enumerable.t()
Opens an HL7 file stream of either :mllp
or :line
. If the file_type is not specified
it will be inferred from the first three characters of the file contents.
@spec put(parsed_hl7(), HL7.Path.t(), String.t() | nil | hl7_map_data()) :: parsed_hl7()
Puts data within an HL7
struct, parsed segments or repetitions
using an HL7.Path
struct (see sigil_p/2
).
Examples
Put field data as a string.
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7()
...> |> new!()
...> |> put(~p"PID-8", "F")
...> |> get(~p"PID-8")
"F"
Put field data as a string overwriting all repetitions.
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7()
...> |> new!()
...> |> put(~p"PID-11[*]", "SOME_ID")
...> |> get(~p"PID-11[*]")
["SOME_ID"]
Put field data into a single repetition.
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7()
...> |> new!()
...> |> put(~p"PID-3[2]", ["a", "b", "c"])
...> |> get(~p"PID-3[2].3")
"c"
Put component data across multiple repetitions.
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7()
...> |> new!()
...> |> put(~p"PID-11[*].3", "SOME_PLACE")
...> |> get(~p"PID-11[*].3")
["SOME_PLACE", "SOME_PLACE"]
Put data in a segment using just the path to a field.
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7()
...> |> new!()
...> |> get(~p"PID")
...> |> put(~p"3", "SOME_ID")
...> |> get(~p"3")
"SOME_ID"
Put data across multiple segments
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7()
...> |> new!()
...> |> put(~p"OBX[*]-5", "REDACTED")
...> |> get(~p"OBX[*]-5")
["REDACTED", "REDACTED"]
Sets a list of sparse maps (with ordinal indices and strings) representing
the parsed segments of an HL7 message to define the content of an HL7
struct.
Sets a map of custom metadata associated with the HL7
struct.
The ~p
sigil encodes an HL7 path into a struct at compile-time to guarantee correctness and speed.
It is designed to work with data returned by HL7.new!/1
, providing a standard way to get and update
HL7 message content.
Importing Just the Sigil
Use import HL7, only: :sigils
to access the ~p
sigil without importing the other HL7
functions.
The full path structure in HL7 is expressed as:
~p"SEGMENT_NAME[SEGMENT_NUMBER]-FIELD[REPETITION].COMPONENT.SUBCOMPONENT
A trailing exclamation mark can be used in the path to the return only the leftmost text at the given level.
Position Name | Valid Values |
---|---|
SEGMENT_NAME | 3 character string |
SEGMENT_NUMBER | Positive integer in square brackets, defaults to 1. All segments of SEGMENT_NAME can be accessed with [*] |
FIELD | Positive integer |
REPETITION | Positive integer in square brackets, defaults to 1. All repetitions of the FIELD can be accessed with [*] |
COMPONENT | Positive integer |
SUBCOMPONENT | Positive integer |
1-based Indexes
To match industry expectations, HL7 uses 1-based indexes. As noted above, it also includes defaults whereby all paths refer to the 1st segment and/or 1st repetition of any query unless explicitly specified.
Example paths:
HL7 Path | Description |
~p"OBX" | The 1st OBX segment in its entirety, the same as ~p"OBX[1]" . |
~p"OBX-5" | The 1st repetition of the 5th field of the 1st OBX segment. |
~p"OBX[1]-5[1]" | Same as above. The numbers in brackets specify the default repetition and segment number values. |
~p"OBX-5[*]" | Every repetition of the 5th field of the 1st OBX segment, returning a list of results. |
~p"OBX[2]-5" | The 1st repetition of the 5th field of the 2nd OBX segment. |
~p"OBX[*]-5" | The 1st repetition of the 5th field of every OBX segment, returning a list of results. |
~p"OBX[*]-5[*]" | Every repetition of the 5th field of every OBX segment, returning a nested list of results. |
~p"OBX-5.2" | The 2nd component of the 1st repetition of the 5th field of the 1st OBX segment. |
~p"OBX-5.2.3" | The 3rd subcomponent of the 2nd component of the 1st repetition of the 5th field of the 1st OBX segment. |
~p"OBX[*]-5.2.3" | Same as above, but returned as a list with a value for each OBX segment. |
~p"OBX[*]-5[*].2.3" | Same as above, but now a nested list of results for each repetition within each segment. |
~p"OBX-5!" | The ! will take the first text (leftmost value) at whatever level is specified. Thus, p"OBX-5!" is equivalent to p"OBX-5.1.1" . |
~p"5" | The fifth field of a segment (parsed as an ordinal map starting with 0) |
~p".2" | The second component of a repetition (parsed as an ordinal map starting with 1) |
Note that repetitions are uncommon in HL7 and the default of a 1st repetition is often just assumed.
~p"PID-3"
is equivalent to ~p"PID-3[1]"
and is the most standard representation.
All repetitions can be found using a repetition wildcard: ~p"PID-11[*]"
. A list of lists can
be produced by selecting multiple segments and multiple repetitions with ~p"PID[*]-11[*]"
.
Components and subcomponents can also be accessed with the path structures.
p"OBX-2.3.1"
would return the 1st subcomponent of the 3rd component of the 2nd field of the 1st OBX.
If dealing with segments or repetitions extracted from parsed HL7, you can use partial paths that
lack the segment name and/or field like ~p"5"
for the fifth field of a segment or ~p".3"
for the 3rd
component of a repetition.
Additionally, if a path might have additional data such that a string might be found at either
~p"OBX-2"
or ~p"OBX-2.1"
or even ~p"OBX-2.1.1"
, there is truncation character (!
) that
will return the first element found in the HL7 text at the target specificity. Thus, ~p"OBX[*]-2!"
would get the 1st piece of data in the 2nd field of every OBX whether it is a string or nested map.
Nil vs Empty String
Paths that query beyond the content of an HL7 document, e.g. asking for the 10th field of a segment with five fields,
will return nil
as opposed to an empty string to indicate that the data does not exist. Adding the
trailing !
to an HL7.Path
will force all return values to be simple strings in cases where nil
is not desired.
Note that it also returns the leftmost text at the path level, discarding extra data as noted above.
Examples
iex> import HL7, only: :sigils
iex> HL7.Examples.wikipedia_sample_hl7() |> HL7.new!() |> HL7.get(~p"OBX-5")
"1.80"
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7() |> new!() |> get(~p"OBX-3")
%{2 => "Body Height"}
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7() |> new!() |> get(~p"PID-11!")
"260 GOODWIN CREST DRIVE"
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7() |> new!() |> get(~p"OBX[*]-5")
["1.80", "79"]
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7() |> new!() |> get(~p"OBX[*]-2!")
["N", "NM"]
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7() |> new!() |> get(~p"PID-11[*].5")
["35209", "35200"]
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7() |> new!() |> get(~p"PID[*]-11[*].5")
[["35209", "35200"]]
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7() |> new!() |> get(~p"PID-11[2].1")
"NICKELL’S PICKLES"
iex> import HL7
iex> HL7.Examples.wikipedia_sample_hl7()
...> |> new!()
...> |> get(~p"PID-11[*]")
...> |> List.last()
...> |> get(~p".1")
"NICKELL’S PICKLES"
@spec to_list(t()) :: hl7_list_data()
Converts an HL7 message struct into a nested list of strings.
@spec update( parsed_hl7(), HL7.Path.t(), String.t() | nil | hl7_map_data(), (hl7_map_data() -> hl7_map_data()) ) :: parsed_hl7()
Updates data within an HL7
struct, parsed segments, or repetitions
using an HL7.Path
struct (see sigil_p/2
).
@spec update!(parsed_hl7(), HL7.Path.t(), (hl7_map_data() -> hl7_map_data())) :: parsed_hl7()
Updates data within an HL7
struct, parsed segments, or repetitions
using an HL7.Path
struct (see sigil_p/2
). Raises a RuntimeError
if the path is not present in the source data.