
Data Types — from ST and NM to XPN, XAD, CX, and CWE
- 6 min
- 7 steps
- 2 questions
- Lesson 5 of 51
In this lesson
- Fields are typed claims
- Primitive types still carry rules
- Composite types preserve context
- Coded values: code, text, and system
- Repetition is not composition
- Absent, empty, null, and unknown
- Build type-focused tests
Picking up where you left off.
Fields are typed claims
The text between two field separators is not merely a string. Each field position has a declared data type that says how to interpret its content. A type may be primitive, such as a number, or composite, such as an identifier plus the authority that issued it. The v2 data-type chapter defines the ordered components and rules that make these values interoperable 1.
Type, field location, table binding, and profile work together. The text F could mean female in an administrative-sex field, final in a result-status field, or something local elsewhere. Never map a value from characters alone.
Primitive types still carry rules
| Type | Purpose | Example | Common trap |
|---|---|---|---|
ST |
short string | Final report |
assuming unbounded length or hidden structure |
TX |
narrative text | Patient reports... |
losing escapes, line structure, or display intent |
NM |
numeric value | 7.4 |
mixing units into the numeric field |
DT |
calendar date | 20260809 |
inventing missing day precision |
DTM |
date and time | 202608091430-0500 |
dropping offset or precision |
ID |
value from an HL7 table | AA |
accepting arbitrary local values |
IS |
value from a user-defined table | I |
assuming two sites use the same local table |
Dates and times deserve special care. A partial precision such as year and month is not the first day of that month. A timestamp without an offset should not be silently labeled UTC. Define time-zone policy, daylight-saving handling, and whether the source can send fractional seconds.
Composite types preserve context
Composite types use ^ between components and & within subcomponents. Empty component positions remain meaningful:
DOE^JANE^Q^^DR^MD
The double caret before DR preserves an empty suffix so that prefix and degree remain in their declared positions.

XPN: a person name is not one label
XPN can carry family name, given name, additional names, suffix, prefix, degree, name type, validity dates, professional suffix, and more depending on version. Names may repeat for legal, alias, maiden, display, or other uses. A receiver that concatenates one preferred string and discards repetitions may lose information needed for matching or respectful display.
Avoid treating names as identifiers. Spelling, order, punctuation, diacritics, and use can change. Preserve components, repetition type, and original text where the contract requires them.
CX: an identifier needs a namespace
A CX value can contain the identifier, check digit information, assigning authority, identifier type, assigning facility, effective dates, and jurisdiction. For example:
100711^^^HOSP^MR
means identifier 100711, assigned under HOSP, with identifier type MR. The string 100711 by itself is not globally meaningful. Another hospital can issue the same number to a different person. The assigning authority is part of the identity claim, not optional decoration.
For matching and deduplication, retain at least the identifier value, authority, type, status or validity where available, and provenance. Never merge patients because two naked numeric strings match.
XCN and XAD: people and addresses in roles
XCN combines a person identifier with name components and is often used for providers. Its role comes from the field containing it: an ordering provider, attending provider, and verifier are not interchangeable simply because all use XCN.
XAD structures an address into street, city, state, postal code, country, address type, validity, and other components. Postal normalization may help matching, but preserve the supplied value and type. An old address, mailing address, and temporary address can all be valid repetitions with different uses.
Coded values: code, text, and system
CWE is a common coded data type. Its core tuple is:
identifier ^ display text ^ name of coding system
For example, a local test code might appear as GLU^Glucose^L. The L says the code belongs to a local system; it does not become LOINC because the display text resembles a LOINC term. The standard permits alternate coding components so a sender can carry both local and standard representations under defined rules 1.
CNE is coded with no exceptions: when populated, the identifier is expected to come from the specified non-extendable value set. CWE allows more flexibility, including exceptions under its rules. Choosing between them expresses a conformance expectation, not a formatting preference.
Three recurring errors are:
- mapping on display text while ignoring the coding system;
- sending a local code with a standard-system label;
- replacing an unknown code with a plausible standard code without review.
Prefer an explicit unmapped or exception workflow over a confident but wrong translation.
Repetition is not composition
The repetition separator ~ means “another value of this field.” The component separator ^ means “another part of this one value.” Compare:
111^^^HOSP^MR~999-88-7777^^^USSSA^SS
This is two CX identifiers, each with its own authority and type. Flattening repetitions into one component list destroys the grouping. Mapping code should iterate repetitions first, then interpret each repetition by its declared data type.
Absent, empty, null, and unknown
An omitted optional field, an empty field, an explicit null instruction, and a coded “unknown” are different states. The exact update semantics must come from the profile and interface agreement. A safe receiver does not automatically turn every blank into “erase the stored value,” nor every unknown into missing data.
Record update behavior field by field:
| Incoming state | Possible contract behavior |
|---|---|
| field omitted | no assertion / leave unchanged |
| empty field | not provided / validate as empty |
| explicit null | remove existing value if the profile permits |
| coded unknown | store the defined unknown concept |
Build type-focused tests
For each consequential field, test:
- minimum, maximum, and invalid length;
- empty and explicit-null behavior;
- multiple repetitions in different orders;
- missing or unfamiliar assigning authority;
- invalid date precision, offset, and daylight-saving boundary;
- code with missing, local, or incorrect coding system;
- Unicode names, punctuation, prefixes, suffixes, and multiple name types;
- a valid base-standard value that the local profile forbids.
Practice
Take PID-3, PID-5, PID-11, and one coded clinical field. For each, write the declared type, the components you will retain, allowed repetitions, terminology or authority rules, null behavior, and one dangerous lossy transformation. Then create a round-trip test: parse the field, store it in your internal model, serialize it again, and compare the semantic structure—not only the printed string.
Practice
The same identifier string can exist in multiple namespaces; the assigning authority makes the identity claim interpretable.
Practice
A code has meaning within a coding system and value-set context; display text is not a stable substitute.
Lesson complete
Nice work.
Sources for this lesson
- 1HL7 Version 2.9 — Chapter 2A: Data Types. HL7 International (HL7 Europe public mirror). 2019. verifiedDefines primitive and composite v2 data types, including CWE, CX, XCN, XPN, identifiers, names, timestamps, coded values, and their components. Cited at: data type definitions; CWE.
Further reading
- HL7 Standards — Section 1d: Version 2 (V2). HL7 International. verifiedThe HL7 Version 2 messaging standard, first released October 1987 and the most widely implemented healthcare messaging standard worldwide.
- Tim Benson, Grahame Grieve. Principles of Health Interoperability: FHIR, HL7 and SNOMED CT. 4th ed. Springer. 2021. verified