Cameleer

HL7 data format

The hl7 data format parses HL7 v2 messages (ER7, the pipe-delimited text) into a structured value with the CamelHL7* headers, and encodes such values back to ER7 text.

Name: hl7 · Crate: cameleer-protocols · Cargo feature: protocols · Apache Camel: HL7

When to use it

  • Integrate hospital systems: admissions (ADT), orders (ORM), results (ORU) and scheduling (SIU) feeds arrive as HL7 v2 over MLLP.
  • Route messages by type and trigger event (ADT^A01 to one system, ORU^R01 to another).
  • Turn lab results into JSON for an analytics pipeline or an assistant that summarizes them for clinicians.

Marshal and unmarshal

directioninput bodyoutput body
unmarshalER7 text (segments separated by CR, LF or CRLF)an object: messageType, triggerEvent, messageControlId, versionId and segments (each {name, fields}); sets the CamelHL7* headers
marshalsuch an object, or ER7 textER7 text with CR segment separators (text bodies are parsed first, so invalid messages fail)

Field values are kept as raw ER7 strings (components joined with ^). To read single fields or components use the hl7terser language (PID-5-1, OBX(1)-5), which works on the ER7 text as well as on the unmarshalled value.

The data format is registered in the registry as hl7 by cameleer-protocols (included in cameleer_main::new_main() and the container image). It has no options.

Example

Unmarshal an admission message and route on the headers.

yaml example: hl7-unmarshal-route
- route:
    id: hl7-adt
    from:
      uri: direct:hl7
      steps:
        - unmarshal:
            hl7: {}
        - choice:
            when:
              - simple: "${header.CamelHL7MessageType} == 'ADT' && ${header.CamelHL7TriggerEvent} == 'A01'"
                steps:
                  - setBody:
                      simple: "admit ${header.CamelHL7MessageControl} from ${header.CamelHL7SendingApplication}: ${body.segments[2].fields[4]}"
            otherwise:
              steps:
                - setBody:
                    simple: "ignored ${header.CamelHL7MessageType}^${header.CamelHL7TriggerEvent}"
text
MSH|^~\&|ADMIT|WARD7|EHR|HOSP|20261105120000||ADT^A01^ADT_A01|MSG00042|P|2.5
EVN|A01|20261105120000
PID|1||12345^^^MRN||Doe^Jane||19800101|F
text
admit MSG00042 from ADMIT: Doe^Jane

Marshal builds ER7 from the structured value, for example a result produced by an AI summarizer that must go back to the EHR as an ORU^R01. MSH field 1 is the field separator itself, as in HL7. The route replaces the CR segment separators with / only so the result fits on one line here.

yaml example: hl7-marshal
- route:
    id: hl7-marshal
    from:
      uri: direct:hl7-marshal
      steps:
        - unmarshal:
            json: {}
        - marshal:
            hl7: {}
        - setBody:
            simple: '${body.replace("\r", " / ")}'
json
{"segments": [
  {"name": "MSH", "fields": ["|", "^~\\&", "SUMMARIZER", "AI", "EHR", "HOSP", "20261105120000", "", "ORU^R01", "MSG8", "P", "2.5"]},
  {"name": "PID", "fields": ["1", "", "12345^^^MRN", "", "Doe^Jane"]},
  {"name": "OBX", "fields": ["1", "TX", "SUMMARY", "", "Glucose within normal range"]}
]}
text
MSH|^~\&|SUMMARIZER|AI|EHR|HOSP|20261105120000||ORU^R01|MSG8|P|2.5 / PID|1||12345^^^MRN||Doe^Jane / OBX|1|TX|SUMMARY||Glucose within normal range /

Rust DSL

rust
b.from("direct:hl7-rust")
    .unmarshal(DataFormatDefinition::named("hl7"))
    .set_body(simple("${header.CamelHL7MessageType}^${header.CamelHL7TriggerEvent}"));

Message headers

Set by unmarshal from the MSH segment:

headerMSH field
CamelHL7SendingApplicationMSH-3
CamelHL7SendingFacilityMSH-4
CamelHL7ReceivingApplicationMSH-5
CamelHL7ReceivingFacilityMSH-6
CamelHL7TimestampMSH-7
CamelHL7SecurityMSH-8
CamelHL7MessageTypeMSH-9-1
CamelHL7TriggerEventMSH-9-2
CamelHL7MessageControlMSH-10
CamelHL7ProcessingIdMSH-11
CamelHL7VersionIdMSH-12
CamelHL7CharsetMSH-18

Differences from Apache Camel

Camel's hl7 data format produces HAPI Message objects with typed segment classes per HL7 version. Here the value is a generic structure (segments and raw fields) and there is no version-specific validation; use terser paths to read fields. Acknowledgements (AA, AE) are generated by the MLLP component (autoAck).

Common questions

How do I receive HL7 messages over MLLP?

Use from: mllp:0.0.0.0:2575 and unmarshal: hl7: {}; the MLLP consumer handles framing and sends the ACK. See the MLLP component.

How do I get the patient name from an HL7 message?

hl7terser: PID-5 gives the whole name field (Doe^Jane), PID-5-1 the family name and PID-5-2 the given name.

Why do my segments run together?

HL7 separates segments with a carriage return (\r). Unmarshal also accepts LF and CRLF; marshal always writes CR, which some viewers show as one line.

Found a problem?

If something on this page doesn't match what Cameleer does, or you hit a bug while building with it, please help fix it, whether you are a person or a coding agent: open an issue that describes what you saw, then fork the repository, fix it, add or update a test, run cargo test --workspace, and open a pull request. CONTRIBUTING.md explains the ground rules.

Edit this page on GitHub