Header delimiters come back literally
MSH-1 is the field separator and MSH-2 is the encoding characters.
They are the delimiters, not values encoded with them, so they are never decoded: MSH-1 gives | and MSH-2 gives ^~\&.
Reference
The short notation that names one place in a message: PID-5.1, OBX[2]-5, PID-13[2].1.
The notation is a de-facto standard among interface engineers rather than part of HL7 itself, so this crate accepts the two spellings that are common in the field and writes the first.
path = name occurrence? ( ("-" | ".") index occurrence? ( "." index ( "." index )? )? )?
name = one or more ASCII letters and digits
occurrence = "[" index "]"
index = a decimal number, 1 or greater Surrounding whitespace is ignored.
| Path | Names | On PID|1||9|4|SMITH^JOHN^Q |
|---|---|---|
PID | every PID segment, whole | PID|1||9|4|SMITH^JOHN^Q |
PID-5 | field 5 | SMITH^JOHN^Q |
PID-5.1 | component 1 of field 5 | SMITH |
PID-5.1.2 | subcomponent 2 of that component | — only one here |
A path that stops above the leaf returns that subtree as written, with its structural delimiters intact. Only the leaf text is decoded.
There are two, and they mean different things.
| Position | Selects | Example |
|---|---|---|
| after the segment name | which segment of that name | OBX[2]-5 — the second OBX |
| after the field number | which repetition of that field | PID-13[2] — the second phone number |
Both are 1-based. Both may be omitted, and omitting one means “every one”. They
compose: OBX[2]-5[1].1.2 is subcomponent 2 of component 1 of the first repetition
of field 5 of the second OBX.
// Three OBX segments, so three answers.
assert_eq!(message.query_all("OBX-5")?, ["187", "102", ""]);
// One, pinned down.
assert_eq!(message.query_all("OBX[2]-5")?, ["102"]); Every index is 1-based, and 0 is rejected with an error rather than clamped — it
is almost always a caller’s off-by-one, and silently reading it as 1 would
return a plausible wrong answer.
A path that stops at the field returns the whole field, repetition separators included. A path that goes deeper splits into one answer per repetition.
// PID-13 is `555-1111~555-2222`
assert_eq!(message.query("PID-13")?.as_deref(), Some("555-1111~555-2222"));
assert_eq!(message.query_all("PID-13.1")?, ["555-1111", "555-2222"]);
assert_eq!(message.query_all("PID-13[2].1")?, ["555-2222"]); This is deliberate: PID-13 as a whole field is a meaningful thing to ask for, and
joining its repetitions back with ~ is the only honest way to return it as one
string.
PID-5.1 and PID.5.1 parse identically. Display writes
the first, and round-tripping through it preserves meaning, because occurrence indices the
path left open are left out rather than defaulted to 1.
let a: er7::Path = "PID.5.1".parse()?;
let b: er7::Path = "PID-5.1".parse()?;
assert_eq!(a, b);
assert_eq!(a.to_string(), "PID-5.1");| Method | Takes | Returns | Decoded | Note |
|---|---|---|---|---|
query | &str | Result<Option<String>, Error> | yes | the first match |
query_all | &str | Result<Vec<String>, Error> | yes | every match |
query_path | &Path | Vec<String> | yes | path parsed once |
query_path_raw | &Path | Vec<String> | no | exactly as sent |
The &str forms parse the path each call and can fail with a bad-path error.
The &Path forms take an already-parsed path, which is what you want when
applying one path to many messages.
let path: er7::Path = "PID-5.1".parse()?;
let names: Vec<String> = messages
.iter()
.flat_map(|message| message.query_path(&path))
.collect(); Path implements Clone, PartialEq, Eq, and Hash, so a set of paths can be map keys or deduplicated.
MSH-1 is the field separator and MSH-2 is the encoding characters.
They are the delimiters, not values encoded with them, so they are never decoded: MSH-1 gives | and MSH-2 gives ^~\&.
Not an empty string — no entry at all. So query_all("OBX-5").len() counts the OBX segments that
actually carried a fifth field, which is usually what you want and occasionally a surprise.
The er7 command’s default output labels every value with the path that
names it, and every one of those labels is a valid query.
er7 message.er7 | grep Cholesterol
#=> OBX[1]-3.2 Cholesterol
er7 --query 'OBX[1]-3.2' message.er7
#=> Cholesterol Quote the path in a shell: [ and ] are glob characters.