hl7v2_parser 0.1.0
hl7v2_parser: ^0.1.0 copied to clipboard
Parse, generate, and access HL7v2 messages in Dart. Lazy parser, typed segment extensions, Terser path access, ACK/NAK generation. Zero dependencies, all platforms.
hl7v2_parser #
Parse, generate, and access HL7v2 messages in pure Dart.
The first comprehensive HL7v2 library for Dart and Flutter. Zero dependencies, all platforms (web, mobile, server). Lazy parser that handles 490K+ messages per second.
No more Python/Java sidecars. If your Flutter app talks to hospital systems (LIS, RIS, analyzers, EMRs), this package gives you native HL7v2 support.
Quick Start #
# pubspec.yaml
dependencies:
hl7v2_parser: ^0.1.0
import 'package:hl7v2_parser/hl7v2_parser.dart';
final raw = 'MSH|^~\\&|LAB|HOSP|EMR|HOSP|20240101120000||ORU^R01|MSG001|P|2.5\r'
'PID|||12345^^^HOSP^MR||DOE^JOHN^A||19800101|M\r'
'OBX|1|NM|WBC^White Blood Cell||7.2|10*3/uL|4.5-11.0|N|||F\r';
final message = Message.parse(raw);
// Index access
print(message.segment('PID')!.field(5).first.value); // DOE^JOHN^A
// Terser path access
print(message.get('PID-5-2')); // JOHN
// Typed segment access
print(message.pid!.patientName); // DOE^JOHN^A (XpnValue)
print(message.pid!.patientName!.givenName); // JOHN
Features #
Parse any HL7v2 message #
Lazy parser — segments are split upfront, fields/components parsed on first access. Custom delimiters and encoding characters are fully supported.
final message = Message.parse(raw);
print(message.messageType); // ORU
print(message.triggerEvent); // R01
print(message.version); // 2.5
print(message.segments.length); // 3
Three ways to access data #
1. Index-based — direct positional access, fastest for known field numbers:
final pid = message.segment('PID')!;
final name = pid.field(5).first.component(1).value; // Family name
2. Terser path — string-based path like PID-5-2, familiar to HL7 developers:
final givenName = message.get('PID-5-2'); // JOHN
message.set('PID-5-2', 'JANE'); // Modify in place
3. Typed segment extensions — named getters with composite data types:
final pid = message.pid!;
print(pid.patientName!.familyName); // DOE
print(pid.patientName!.givenName); // JOHN
print(pid.dateOfBirth); // 19800101
print(pid.administrativeSex); // M
Generate HL7v2 wire format #
Round-trip fidelity: Message.parse(raw).encode() == normalize(raw) for all
tested messages. Trailing empty fields are stripped at every level.
final encoded = message.encode();
// MSH|^~\&|LAB|HOSP|EMR|HOSP|20240101120000||ORU^R01|MSG001|P|2.5\r...
Build messages from scratch #
Fluent builder API with automatic MSH-7 (timestamp) and MSH-10 (control ID) generation.
final msg = MessageBuilder()
.msh((b) => b
.sendingApplication('LAB')
.sendingFacility('HOSP')
.receivingApplication('EMR')
.receivingFacility('HOSP')
.messageType('ORU', 'R01')
.version('2.5'))
.addSegment('PID', (b) => b
.field(3, '12345^^^HOSP^MR')
.field(5, 'DOE^JOHN^A')
.field(7, '19800101')
.field(8, 'M'))
.addSegment('OBX', (b) => b
.field(1, '1')
.field(2, 'NM')
.field(3, 'WBC^White Blood Cell')
.field(5, '7.2')
.field(6, '10*3/uL')
.field(7, '4.5-11.0')
.field(8, 'N')
.field(11, 'F'))
.build();
ACK/NAK generation #
Generate acknowledgement messages per HL7v2 spec. Supports both original mode (AA/AE/AR) and enhanced mode (CA/CE/CR).
final ack = message.generateAck(code: AckCode.aa);
print(ack.get('MSA-1')); // AA
print(ack.get('MSA-2')); // MSG001 (echoes original control ID)
// Rejection with error message
final nak = message.generateAck(
code: AckCode.ar,
errorMessage: 'Unknown patient ID',
);
Structural validation #
Validate messages against segment definitions — required fields, data types, max lengths, unknown segments.
final errors = message.validate();
for (final error in errors) {
print('${error.severity}: ${error.message} '
'(${error.segment}:${error.fieldNumber})');
}
Escape handling #
Full HL7v2 escape sequence support including \F\, \S\, \R\, \E\, \T\,
hex (\Xhh\), and custom-delimiter escapes. Automatic unescape on read,
escape on write.
// Raw value preserves escapes, .value unescapes
final raw = pid.field(5).first.rawValue; // Smith\T\Jones
final val = pid.field(5).first.value; // Smith&Jones
25 typed segment extensions #
Named getters for commonly used segments. Composite data types (XPN, CWE, CX, XAD, etc.) are returned as typed objects with named component access.
| Segment | Description |
|---|---|
| MSH | Message Header |
| PID | Patient Identification |
| PV1 | Patient Visit |
| OBR | Observation Request |
| OBX | Observation/Result |
| ORC | Common Order |
| MSA | Message Acknowledgement |
| EVN | Event Type |
| ERR | Error |
| NK1 | Next of Kin |
| AL1 | Allergy Information |
| DG1 | Diagnosis |
| FT1 | Financial Transaction |
| GT1 | Guarantor |
| IAM | Patient Adverse Reaction |
| IN1 | Insurance |
| MRG | Merge Patient Information |
| NTE | Notes and Comments |
| PD1 | Patient Additional Demographics |
| ROL | Role |
| RXA | Pharmacy/Treatment Administration |
| RXO | Pharmacy/Treatment Order |
| SCH | Scheduling Activity Information |
| SPM | Specimen |
| TXA | Transcription Document Header |
Z-segments parse transparently — access their fields by index or Terser path.
16 composite data types #
XpnValue, CweValue, CxValue, XadValue, XcnValue, XtnValue,
HdValue, EiValue, PlValue, PtValue, VidValue, MsgValue,
CqValue, ErlValue, FcValue, SnValue — all with named component getters
and automatic unescaping.
Benchmarks #
Measured on Apple M-series, Dart 3.8.1 (stable), macOS. Each benchmark runs for ≥3 seconds after 100 warmup iterations.
| Benchmark | msg/s | avg latency |
|---|---|---|
| Parse ADT^A01 (6 segments) | 493,908 | 2.0 µs |
| Parse ORM^O01 (7 segments) | 508,266 | 2.0 µs |
| Parse ORU^R01 (11 segments) | 442,369 | 2.3 µs |
| Parse Large ORU (55 segments) | 80,878 | 12.4 µs |
| Round-trip ADT^A01 | 34,925 | 28.6 µs |
| Round-trip ORU^R01 | 30,859 | 32.4 µs |
| Terser 10-path lookup | 165,333 | 6.0 µs |
Platform Support #
| Platform | hl7v2 | hl7v2_mllp |
|---|---|---|
| Dart VM (server) | Yes | Yes |
| Flutter (Android/iOS) | Yes | Yes |
| Flutter Web | Yes | No* |
| Dart CLI | Yes | Yes |
* hl7v2_mllp requires dart:io for TCP sockets. Core parsing works
everywhere.
MLLP Transport #
For TCP transport over MLLP (client, server, TLS, reconnection), see the
companion package hl7v2_mllp.
Comparison #
| Feature | hl7v2 | hl7_v2 v0.0.1 |
|---|---|---|
| Parse ER7 | Yes | Yes |
| Generate ER7 | Yes | No |
| Terser paths | Yes | No |
| Typed segments | 25 | 0 |
| Composite types | 16 | 0 |
| ACK/NAK generation | Yes | No |
| Message builder | Yes | No |
| Validation | Yes | No |
| Escape sequences | Full | Partial |
| Custom delimiters | Yes | No |
| MLLP transport | Separate pkg | No |
| Zero dependencies | Yes | No |
| Web platform | Yes | No |
| Benchmark (msg/s) | 490K+ | — |
Contributing #
Contributions welcome! Areas of interest:
- Additional typed segment extensions (120+ segments in the HL7v2 spec)
- Version-specific schema validation
- Additional test fixtures from real hospital systems
Please file issues on GitHub.
License #
BSD-3-Clause. See LICENSE.