Examples
Examples
Short, copyable snippets grouped by what you are trying to do. Each links to the guide that explains it; nothing here is a substitute for reading the crate's own specification.
Reading a message
Parse — see Parsing.
Parse, and read the structure the header claims
use hl7::v2;
let message = v2::parse(text)?;
assert_eq!(message.structure_id(), "ORU_R01");Force a release when MSH-12 lies
use hl7_2::Version;
let options = hl7_2::Options::new().with_version(Version::V2_3);
let message = hl7_2::parse_with_options(text, &options)?;Read — see Navigating.
One value, by path
let family = message.get("PID-5.1")?; // Option<String>
let second = message.get("OBX[2]-5.2")?; // the second OBX
let deep = message.get("PID-3.4.2")?; // down to a subcomponentEvery value, and every repetition
let all = message.get_all("OBX-5")?; // every OBX's field 5
let reps = message.repetitions("PID-3")?; // every repetition of one fieldWalk the tree, and ask each node its own path
for observation in message.tree().find_all("OBX") {
println!("{} = {}", observation.path(), observation.text());
}Ask the dictionary what a field is
// What does the dictionary say this field is?
assert_eq!(message.type_of("PID-3")?.as_deref(), Some("CX"));A file holding one message, several, or a batch
for text in hl7_2::split_messages(batch) {
match hl7_2::parse(&text) {
Ok(message) => handle(&message),
Err(error) => eprintln!("skipping: {error}"),
}
}Writing and answering
Set, null, and clear
let mut message = hl7_2::parse(text)?;
message.set("PID-5.2", "EVELYN")?; // delimiters in the value are escaped
message.set_null("PID-11")?; // the explicit HL7 null
message.clear("PID-12")?; // remove the value entirelyAdd a segment, then render
message.append_segment("NTE");
message.set("NTE[2]-1", "2")?;
message.set("NTE[2]-3", "Amended after review.")?;
let er7 = message.to_er7();Build a message from nothing
let message = hl7_2::Builder::new(hl7_2::Version::V2_5)
.message_type("ADT", "A01")
.control_id("MSG00042")
.timestamp("20260814080000")
.sending("MYAPP", "MYFACILITY")
.receiving("EHR", "CLINIC")
.processing_id("P")
.segment("PID")
.set("PID-5.1", "EVERYWOMAN")
.build_valid()?;Acknowledge, echoing the control ID
let ack = hl7_2::builder::acknowledge(&message, "AA", "ACK00001", "20260814080100")
.build_valid()?;
assert_eq!(ack.get("MSA-2")?.as_deref(), Some("MSG00042"));Check — see Validating.
Diagnostics, split by severity
for diagnostic in message.validate() {
println!("{diagnostic}");
}
let clean = message
.validate()
.iter()
.all(|d| d.severity != hl7_2::Severity::Error);Refuse anything that does not conform, up front
let options = hl7_2::Options::new().strict();
match hl7_2::parse_with_options(text, &options) {
Ok(message) => { /* conformant */ }
Err(hl7_2::Error::Invalid(diagnostics)) => { /* every error-level finding */ }
Err(other) => { /* not a message at all */ }
}Dialects and dictionaries
See Vendor dictionaries.
A dialect stated inline
use std::sync::Arc;
let dictionary = hl7_2::Dictionary::from_json(r#"{
"inherits": "2.5",
"segments": { "ZAC": ["SI", "XPN", "DT"] }
}"#, "acme")?;
let options = hl7_2::Options::new().with_dictionary(Arc::new(dictionary));
let message = hl7_2::parse_with_options(text, &options)?;A dialect from a file, and reading it back
let text = std::fs::read_to_string("acme.json")?;
let dictionary = hl7_2::Dictionary::from_json(&text, "acme")?;
assert_eq!(dictionary.field_type("PID", 3), Some("CX"));
assert!(dictionary.field_cardinality("PID", 3).repeats);Generate one from a directory of XSDs
use hl7_2_from_xsd_into_json_dictionary::{Options, convert_directory};
let document = convert_directory("schemas/paris".as_ref(), &Options::default())?;
std::fs::write("paris.json", document.to_json())?;Typed structs
Read into a struct, keeping the escape hatch
use hl7_2::{FromHl7, Raw};
#[derive(FromHl7)]
struct Admission {
#[hl7("PID-3.1")] patient_id: String,
#[hl7("PID-7.1")] birth_date: Option<String>,
#[hl7("PID-3")] all_identifiers: Vec<String>,
#[hl7(raw)] raw: Raw,
}
let admission: Admission = hl7_2::parse(text)?.decode()?;
assert_eq!(admission.raw.get("ZPD-1")?.as_deref(), Some("local"));Write a struct out into a message
use hl7_2::{FromHl7, ToHl7};
#[derive(FromHl7, ToHl7)]
struct Patient {
#[hl7("PID-5.1")] family: String,
#[hl7("PID-8")] sex: Option<String>,
}
let message = hl7_2::Builder::new(hl7_2::Version::V2_5)
.message_type("ADT", "A01")
.control_id("1")
.segment("PID")
.encode(&patient)
.build_valid()?;Converting formats
See Converting formats.
ER7 into XML and JSON
let xml = hl7_2_from_er7_into_xml::convert(er7)?;
let json = hl7_2_from_er7_into_json::convert(er7)?;With options
use hl7_2_from_er7_into_json::{Options, convert_with_options};
let json = convert_with_options(er7, &Options { flat: true, compact: true })?;And back again
let er7 = hl7_2_from_xml_into_er7::convert(xml)?;
let er7 = hl7_2_from_json_into_er7::convert(json)?;
// Or keep the message, to query or edit it:
let message = hl7_2_from_xml_into_er7::parse(xml)?;
assert_eq!(message.query("PID-5.1")?.as_deref(), Some("TEST"));Transports
Frame one message
use hl7_2_mllp as mllp;
let frame = mllp::encode(message.as_bytes());
assert_eq!(mllp::decode(&frame)?, message.as_bytes());Reassemble a chopped-up stream
use hl7_2_mllp::Framer;
let mut framer = Framer::new();
framer.push(b"\x0bMSH|one\x1c\r\x0bMSH|t");
framer.push(b"wo\x1c\r");
assert_eq!(framer.next_frame()?.unwrap(), b"MSH|one");
assert_eq!(framer.next_frame()?.unwrap(), b"MSH|two");
assert_eq!(framer.next_frame()?, None);Serve MLLP over TCP
use hl7_2_mllp::{IoTransport, Transport};
use std::net::TcpListener;
let listener = TcpListener::bind("127.0.0.1:2575")?;
for stream in listener.incoming() {
let mut transport = IoTransport::new(stream?);
while let Some(message) = transport.receive()? {
// ... one whole HL7 message ...
}
}Receive a SOAP request
use hl7_2_soap::{Fault, message};
fn accept(request_body: &str) -> Result<String, Fault> {
let envelope = hl7_2_soap::parse(request_body)?;
let payload = envelope.payload()?;
message::check(payload, &["ADT_A05".to_string()], &[])?;
Ok(message::control_id(payload).unwrap_or_default().to_string())
}Send one, and read the reply
use hl7_2_soap::{message, response::{self, Outcome}};
let body = message::wrap_er7("MSH|^~\\&|APP||||1||ADT^A01|9|P|2.5");
match response::evaluate(status, &reply) {
Outcome::Accepted => {}
Outcome::Rejected(reason) => eprintln!("not delivered: {reason}"),
}HL7 v3
See HL7 v3.
Read the three-level envelope
use hl7_3::message;
let parsed = message::parse(xml)?;
let observation = parsed.control_act.unwrap().domain.unwrap();
let act = hl7_3::rim::Act::from_element(&observation);
assert_eq!(act.class_code, "OBS");Data types, and explicit absence
use hl7_3::{Ivl, NullFlavor, Pq};
let dose = hl7_3::xml::parse(r#"<doseQuantity value="5" unit="mg"/>"#)?;
assert_eq!(Pq::from_element(&dose).unit.as_deref(), Some("mg"));
let value = hl7_3::xml::parse(r#"<value nullFlavor="ASKU"/>"#)?;
assert_eq!(NullFlavor::of(&value), Some(NullFlavor::AskedButUnknown));The shared XML reader, on its own
let xml = r#"<order id="7"><item qty="2">widget</item></order>"#;
let root = hl7_2_xml_lite_helper::parse(xml)?;
assert_eq!(root.attribute("id"), Some("7"));
assert_eq!(root.child("item").unwrap().text, "widget");
assert_eq!(root.find("item").unwrap().text, "widget"); // first descendantShell one-liners
See Command line.
# Look at an unfamiliar message
hl7-v2 --paths message.hl7
# Every result value in a directory
cat inbox/*.hl7 | hl7-v2 --query OBX-5
# Check, with an exit status a script can act on
hl7-v2 --check message.hl7
# Read a vendor dialect
hl7-v2 --dictionary acme.json message.hl7
# Edit and re-emit
hl7-v2 --set 'PID-8=F' --er7 message.hl7
# Convert, both ways
hl7-2-from-er7-into-xml message.hl7 > message.xml
hl7-2-from-xml-into-er7 message.xml
# Round trip as a smoke test
hl7-2-from-er7-into-xml message.hl7 | hl7-2-from-xml-into-er7 | diff - <(hl7-v2 --er7 message.hl7)Runnable examples in the repository
hl7-2-mllp ships two programs that talk to each other. The listener is commented
with what it shows and what a production listener also needs — worth reading before writing your
own.
# Two programs that talk to each other
cd hl7-2-mllp
cargo run --example tcp_listener # accepts, reads, acknowledges
cargo run --example tcp_sender # sends, waits, checks the echoSeveral crates also carry a samples/ directory — real ER7 files, and the exact XML
and JSON documents the golden tests produce. They are the fastest way to see what a conversion
actually emits.