Help
FAQ
The questions that come up before the first line of code, and a few that come up on the second day.
Choosing
Which crate should I depend on?
hl7, and use hl7::v2. It is a thin re-export of hl7-2, where essentially all the v2 capability lives.
Depend on hl7-2 directly if you want one standard with no umbrella indirection —
there is no functional difference.
Do I have to take all fourteen crates?
No. Each is a layer you can stop at. Most integrations use one or two: hl7 plus a transport, or just one conversion binary and no Rust at all. See Architecture.
Which parsing mode should I start in?
Generic, always — even when you know the feed. It rejects nothing, so it is the mode you explore in. Schema mode and struct mode are what you graduate to. See Parsing.
Is there an async API?
No. The parsing crates are synchronous and CPU-bound, and hl7-2-mllp's IoTransport works over any Read + Write. Wrapping the
transport for an async runtime is left to you rather than being baked in, so the crate does not
pick a runtime on your behalf.
HL7 v2
Which HL7 releases are supported?
The fourteen published releases from 2.1 to 2.9. v2.5 is the complete base; every other release is a delta of it. See Versions and compatibility.
The sender's MSH-12 says 2.3 but they send 2.5 fields. What do I do?
Believe the content, not the declaration, and force the release:
let options = hl7_2::Options::new().with_version(hl7_2::Version::V2_5);
let message = hl7_2::parse_with_options(text, &options)?;My message has a Z-segment. Will it parse?
Yes, and it will not even produce a warning — the standard says nothing about Z-segments, so
neither does this crate. The fields read positionally
(ZDS.1, ZDS.1.1) until you write a dictionary that names them.
Why did my message render flat instead of grouped?
Because its segments did not fit the structure MSH-9 declared — usually a
Z-segment, or a structure with no built-in grammar. Flat is well-formed and lossless; only the
nesting is missing. Paths are unaffected either way.
How do I tell an explicit HL7 null from an empty field?
// get returns the text at a path, and an explicit null and an empty
// field both come back as an empty string. When the difference matters,
// read the node from the tree instead of the value from the path.
let node = message.tree().find("PID.2");In an update message that difference is the difference between leaving a value alone and erasing it. See the HL7 null.
Why does PID-3.1 give me the wrong identifier?
Because PID-3 repeats, and an unindexed path reads the first repetition. Read all of
them and select by assigning authority — PID-3[n].4. See Navigating.
Is it a validator?
hl7-2 checks a message against its dictionary and reports diagnostics, split into
errors (the message contradicts the dictionary) and warnings (the dictionary does not cover the
message). It does not check HL7 table membership, field lengths, or clinical sense. The four
conversion crates check nothing at all.
Formats and conversion
Is the conversion lossless?
For values, yes, with two documented exceptions: a repetition that was present but entirely blank is dropped by the forward encoding, and — in JSON only — a segment name that repeats non-adjacently loses its place in the sequence. See Converting formats.
Why is there no official “v2.json”?
Because HL7 never defined one. The mapping here is this project's own, designed to preserve everything the official v2.xml encoding preserves while using idiomatic JSON.
Why is every JSON value a string?
HL7 numeric text carries leading zeros, explicit signs, and trailing precision. A JSON number would silently destroy all three, and a lost leading zero in an identifier is a wrong patient.
The round trip does not match my input file byte for byte.
It is not supposed to. The output is the original message canonicalized. Compare against hl7-v2 --er7 input.hl7 rather than against
the raw file. See A lossless round trip.
Can I convert against my vendor's XSDs rather than the bundled v2.5 tables?
Yes — generate a dictionary with hl7-2-from-xsd-into-json-dictionary, and pass --dictionary (and, for schema-shaped output, --schema-shape) to the converter.
HL7 v3 and FHIR
How complete is the v3 support?
It is a foundation: the RIM backbone classes, the data types, and the three-level envelope. No
specific interaction, no vocabulary validation, no CDA document model, and no writing. Read hl7-3's spec/index.md §1 before depending
on it.
Can I write HL7 v3 XML?
Not yet. hl7-3 reads; there is no XML-writing capability, which is also why there
is no #[derive(ToElement)].
Does hl7's derive feature give me the v3 macro?
No — it forwards to hl7-2's only. Enable derive on hl7-3 for #[derive(FromElement)].
Is FHIR supported?
Not yet. The umbrella crate deliberately leaves hl7::fhir free so it can land there
when it is implemented, alongside hl7::v2 and hl7::v3.
Transports
Does the MLLP crate do TLS?
No, and it should not — compose it. IoTransport takes any stream, so a TLS stream
from whichever TLS crate you already audit drops straight in.
My sender omits the trailing <CR>. Can I accept that?
Yes: Framer::new().with_tolerance(Tolerance::Lenient), per connection. Prefer that
over the crate-wide noncompliance feature, which loosens every connection at once.
When should I send AA?
After the message is persisted, not after it parses. AA tells the sender they may
forget it. AE means there is an error in their message; AR means you
are rejecting for reasons unrelated to its content — say the true one, because their retry logic
depends on it.
Do the SOAP crates include an HTTP server?
No. They turn bytes into meaning and back, and leave the socket to whatever you already use.
The project itself
What is the minimum Rust version?
Current stable minus three releases, pinned in every crate. Raising it is treated as a breaking change. See Versions and compatibility.
Why five licenses?
So you can pick the one your organization has already cleared. OR means exactly
that: comply with one, and you do not have to say which.
Why are the dependency counts so small?
Healthcare software gets audited, and a dependency tree is part of what gets audited. The JSON
reader in hl7-2, the JSON writer in the dictionary builder, and the shared XML reader
are all hand-written for that reason.
Where does er7 live?
In er7-rust/er7-rust — its own repository in its own organization, outside this workspace, because plenty of people want the ER7 encoding without the HL7 dictionary.