Crates

hl7-2-from-xml-into-er7

v2.xml XML → ER7

Format conversions v0.6.0 CLI: hl7-2-from-xml-into-er7 Specified

Install cargo add hl7-2-from-xml-into-er7
Rust path hl7_2_from_xml_into_er7
Dependencies er7,hl7-2-xml-lite-helper
Links crates.io docs.rs source spec

What it is

Convert HL7 v2.5 messages from the official HL7 v2.xml XML representation (urn:hl7-org:v2xml) back to the traditional pipe-delimited ER7 encoding, as a Rust library and command-line tool.

It is the inverse of hl7-2-from-er7-into-xml, and it reads back exactly what that crate writes.

Why it needs no dictionary

Which is why this crate is so much smaller than its forward counterpart: reversal is a purely structural, position-based rebuild. It depends on er7 for the encoding layer and, since 0.5.0, on hl7-2-xml-lite-helper for reading the XML — it used to carry its own minimal XML reader.

What it produces

A v2.xml fragment such as:

xml
<PID>
  <PID.1>1</PID.1>
  <PID.3>
    <CX.1>241900</CX.1>
  </PID.3>
  <PID.5>
    <XPN.1>
      <FN.1>TEST</FN.1>
    </XPN.1>
    <XPN.2>FOUAZ</XPN.2>
  </PID.5>
</PID>

converts back to:

er7
PID|1||241900||TEST^FOUAZ

Command line

sh
# From a file to stdout
hl7-2-from-xml-into-er7 samples/orm_o01.xml

# From stdin, to a file
cat samples/oru_r01.xml | hl7-2-from-xml-into-er7 -o out.hl7

# Choose the segment terminator
hl7-2-from-xml-into-er7 --terminator crlf samples/orm_o01.xml

Message-structure group elements (<ORM_O01.PATIENT>, <ORU_R01.ORDER_OBSERVATION>, …) are flattened automatically; grouped and --flat input from the forward crate both reconstruct the same message.

Namespace prefixes are ignored: a document that binds urn:hl7-org:v2xml to a prefix converts to exactly the same ER7 as one that makes it the default namespace, whatever prefix the sending system happened to pick.

Library

rust
let xml = r#"<ORM_O01 xmlns="urn:hl7-org:v2xml">
  <MSH>
    <MSH.1>|</MSH.1>
    <MSH.2>^~\&amp;</MSH.2>
    <MSH.9><MSG.1>ORM</MSG.1><MSG.2>O01</MSG.2></MSH.9>
  </MSH>
  <ORM_O01.PATIENT>
    <PID><PID.5><XPN.1><FN.1>TEST</FN.1></XPN.1><XPN.2>FOUAZ</XPN.2></PID.5></PID>
  </ORM_O01.PATIENT>
</ORM_O01>"#;

let er7 = hl7_2_from_xml_into_er7::convert(xml)?;
rust
use hl7_2_from_xml_into_er7::parse;

// When you want the full er7::Message — to query or edit it — rather than
// just its ER7 text.
let message = parse(xml)?;
assert_eq!(message.query("PID-5.1")?.as_deref(), Some("TEST"));

convert, convert_with_options, and parse return Result<_, Hl7Error>; an Err only ever means the input is not well-formed XML, or the message has no usable MSH/FHS/BHS header. Everything else converts, falling back gracefully rather than failing.

convert_with_options takes the segment terminator, as er7::RenderOptions, re-exported here as hl7_2_from_xml_into_er7::er7::RenderOptions.

What it does

  • XML reading for exactly the subset v2.xml uses: nested elements, text, the predefined entities and numeric character references, with attributes, comments, and the XML declaration recognized and skipped.
  • Position-based reconstruction, no data-type dictionary — see above.
  • Group flattening: message-structure group elements are recognized by their dotted name and flattened back into a plain segment sequence. No message-structure grammar is needed in this direction.
  • Delimiter recovery: the header's .1 and .2 fields are reassembled into a synthetic header line and handed to er7::Separators::from_header, reusing er7's own delimiter parsing.
  • Faithful re-escaping: decoded leaf text is retokenized against er7's own escape-sequence vocabulary, so delimiter characters are re-escaped while formatting sequences the forward crate never decoded (\.br\, \H\, …) are written back exactly as they were.
  • HL7 null versus empty: an element whose text is "" reconstructs as the explicit null (“delete this”); a self-closing or empty element reconstructs as an empty value (“nothing was sent”). The XML Encoding Rules give the two opposite meanings, so this crate keeps them apart — padding an XSD-shaped document with empty elements does not turn it into a message full of deletion markers.

Limitations

  • A field repetition that was present but entirely blank (not the explicit null) is dropped by the forward crate's own encoding and cannot be recovered here — a property of v2.xml as that crate writes it, not something this crate's reversal introduces.
  • One v2.xml document converts to one ER7 message; there is no batch-file convention on the XML side to split.

See spec/index.md §5 for the full list.