Rust crate & CLI · v0.1.1

er7

Parse, query, edit, and write HL7 v2 messages in the ER7 pipe-hat encoding — with a byte-for-byte round trip and zero dependencies.

MSH|^~\&|LAB|ACME|EHR|CLINIC|20260815081500||ORU^R01^ORU_R01|MSG00042|P|2.5
PID|1||444333222^^^ACME&1.2.840.114398.1.100&ISO^MR||EVERYWOMAN^EVE^E||19620320|F
OBX|1|NM|2093-3^Cholesterol^LN||187|mg/dL|<200|N|||F

A lab result: who sent it, who the patient is, and what the cholesterol was. Delimiters in amber, segment names in blue. The same content in HL7’s XML encoding runs to several kilobytes.

The problem Every value’s meaning comes from its position

PID-5.1 is a family name because it is fifth and first, not because anything in the message says so. One misplaced | silently shifts everything after it, and a message that arrives correct but leaves altered is worse than one that fails to parse — because the failure is visible and the alteration is not.

This crate makes that structure explicit and keeps it intact. Text is stored exactly as it arrived and decoded only when you ask for a value.

0 dependencies, guaranteed by a test
6 levels, from message to subcomponent
25 numbered rules, each with a test
1:1 byte-for-byte round trip

Command line Read a message without counting pipes

The default output is an outline: one line per value, labelled with the HL7 path that names it. Every label is a valid query, so you can read a path off the output and paste it straight back in.

er7 samples/oru_r01.er7
MSH-1       |
MSH-2       ^~\&
MSH-3       LAB
MSH-9.1     ORU
MSH-9.2     R01
MSH-9.3     ORU_R01
MSH-10      MSG00042
PID-3.1     444333222
PID-3.4.1   ACME
PID-3.4.2   1.2.840.114398.1.100
PID-5.1     EVERYWOMAN
PID-5.2     EVE
PID-13[1]   555-555-1111
PID-13[2]   555-555-2222
OBX[1]-3.2  Cholesterol
OBX[1]-5    187
OBX[2]-3.2  Triglycerides
Then query it
# One value
er7 --query PID-5.1 message.er7
#=> EVERYWOMAN

# Every observation in a result
er7 --query OBX-5 message.er7
#=> 187
#=> 102

# Exactly as sent, escapes intact
er7 --raw --query OBX-5 message.er7

# Canonical ER7, readable in a terminal
er7 --normalize --terminator lf message.er7

# The second message of a batch file
cat batch.er7 | er7 --message 2

Full command-line reference →

Library Query by path, or walk the tree

let message = er7::parse(text)?;

assert_eq!(message.control_id().as_deref(), Some("MSG00042"));
assert_eq!(message.query("PID-5.1")?.as_deref(), Some("EVERYWOMAN"));
assert_eq!(message.query("OBX-3.2")?.as_deref(), Some("Cholesterol"));

// What went in comes back out, byte for byte.
assert_eq!(message.to_er7(), text);

query returns the first match and query_all returns every one, so OBX-5 across a result with three observations gives three values. When you need the node itself — to edit it, or to ask whether it is an explicit null — walk the tree with 1-based accessors that match HL7’s own numbering.

Full API surface →

Design Three properties, in priority order

Fidelity

Any message the crate reads, it can write back unchanged — unusual delimiters, unknown segments, empty positions, escape sequences and all. Leaf text is stored raw and decoded on demand, which is what makes that possible.

Rule R16

Distinction

Absent, empty, and the explicit null "" are three different answers, not one. The null means clear this value; collapsing it into “empty” leaves a withdrawn allergy on a patient record.

Rules R10, R11

Tolerance

Below the header, nothing fails. Unknown segments, local Z segments, ragged field counts, and undecodable escapes are all data. A receiver that rejects a message it could have read drops clinical information.

Rule R6

Scope An encoding, not a dictionary

This crate does not know what PID-5 means. It does not carry segment definitions, data types, message structures, or code tables — all of that is specific to an HL7 version, while the ER7 encoding is shared by every release from v2.1 to v2.9.

Keeping them apart means the encoding is maintained and tested once, and a dictionary crate can choose its own version. See the ecosystem for the crates built on top: the HL7 v2.5 dictionary, and tools such as er7-redact and serde-er7.

Install Get started

Library
cargo add er7
Command-line tool
cargo install er7