3 releases (breaking)
0.3.0 | Feb 24, 2025 |
---|---|
0.2.0 | Jan 13, 2024 |
0.1.0 | Jan 12, 2024 |
#358 in Parser implementations
178 downloads per month
225KB
4.5K
SLoC
hl7-parser

Parses the structure of HL7v2 messages, but does not validate the correctness of the messages.
[!WARNING]
Although a best effort has been made to make this parse HL7v2 messages correctly, there are no guarantees that it is actually correct. Use at your own risk.
Features
- Parse HL7v2 messages into a structure that can be queried
- Parse HL7v2 timestamps into chrono, time, and jiff types
- Decode HL7v2 encoded strings
- Locate a cursor within a message based on a character index
- Optional lenient parsing of segment separators (allow
\r\n
,\n
, and\r
to count as segment separators instead of just\r
) - Non-ASCII/UTF-8 encodings
(Unchecked features are not yet implemented, but planned for future releases).
Usage
Add this to your Cargo.toml
:
[dependencies]
hl7-parser = "0.3"
and then you can parse HL7v2 messages:
use hl7_parser::{Message, datetime::TimeStamp};
use std::str::FromStr;
let message =
Message::parse("MSH|^~\\&|foo|bar|baz|quux|20010504094523||ADT^A01|1234|P|2.3|||").unwrap();
let msh = message.segment("MSH").unwrap();
assert_eq!(msh.field(3).unwrap().raw_value(), "foo");
let message_time = msh.field(7).unwrap();
let time: TimeStamp = message_time.raw_value().parse().unwrap();
assert_eq!(time.year, 2001);
assert_eq!(time.month, Some(5));
assert_eq!(time.day, Some(4));
Optional Cargo Features
By default, no optional features are enabled.
serde
: enable serde support for all data structurestime
: enable time support for parsing timestampschrono
: enable chrono support for parsing timestampsjiff
: enable jiff support for parsing timestamps
Additional Examples
Querying a Message
let message =
hl7_parser::Message::parse("MSH|^~\\&|foo|bar|baz|quux|20010504094523||ADT^A01|1234|P|2.3|||").unwrap();
let field = message.query("MSH.3").unwrap().raw_value();
assert_eq!(field, "foo");
let component = message.query("MSH.7.1").unwrap().raw_value();
assert_eq!(component, "20010504094523");
Locating the Cursor Within A Message
(The cursor being the character index of some point within the buffer)
let message = Message::parse("MSH|^~\\&|asdf\rPID|1|0").unwrap();
let cursor = locate_cursor(&message, 19).expect("cursor is located");
assert_eq!(cursor.segment.unwrap().0, "PID");
assert_eq!(cursor.segment.unwrap().1, 1);
assert_eq!(cursor.field.unwrap().0, 1);
assert_eq!(cursor.field.unwrap().1.raw_value(), "1");
Decoding Encoded Strings
use hl7_parser::message::Separators;
let separators = Separators::default(); // or, from a parsed message
let input = "foo|bar^baz&quux~quuz\\corge\rquack\nduck";
let expected = r"foo\F\bar\S\baz\T\quux\R\quuz\E\corge\X0D\quack\X0A\duck";
let actual = separators.encode(input).to_string();
assert_eq!(expected, actual);
Parsing Timestamps
use hl7_parser::datetime::{parse_timestamp, TimeStamp, TimeStampOffset};
let ts: TimeStamp = parse_timestamp("20230312195905.1234-0700", false).expect("can parse timestamp");
assert_eq!(ts.year, 2023);
assert_eq!(ts.month, Some(3));
assert_eq!(ts.day, Some(12));
assert_eq!(ts.hour, Some(19));
assert_eq!(ts.minute, Some(59));
assert_eq!(ts.second, Some(5));
assert_eq!(ts.microsecond, Some(123_400));
assert_eq!(ts.offset, Some(TimeStampOffset {
hours: -7,
minutes: 0,
}));
These TimeStamp
values can then be converted to and from chrono
, time
,
and jiff
types if the corresponding features are enabled using std::convert::From
and std::convert::TryFrom.
Building HL7 messages
use hl7_parser::builder::prelude::*;
let message = MessageBuilder::new(Separators::default())
.with_segment(SegmentBuilder::new("MSH")
.with_field_value(3, "SendingApp")
.with_field_value(4, "SendingFac")
.with_field_value(5, "ReceivingApp")
.with_field_value(6, "ReceivingFac")
.with_field(9,
FieldBuilder::default()
.with_component(1, "ADT")
.with_component(2, "A01"))
.with_field_value(10, "123456")
.with_field_value(11, "P")
.with_field_value(12, "2.3"))
.with_segment(SegmentBuilder::new("PID")
.with_field_value(3, "123456")
.with_field(5,
FieldBuilder::default()
.with_component(1, "Doe")
.with_component(2, "John"))
.with_field_value(7, "19700101"))
.render_with_newlines().to_string();
assert_eq!(message,
"MSH|^~\\&|SendingApp|SendingFac|ReceivingApp|ReceivingFac|||ADT^A01|123456|P|2.3\nPID|||123456||Doe^John||19700101");
Dependencies
~1–3MB
~57K SLoC