Skip to end of metadata
Go to start of metadata

HL7 v2 Message Validation

This chapter describes how IPF supports the validation of HL7 v2 messages.


Overview

HL7 v2.x is a complex flat-file structure that, despite being considered a data standard, is also highly flexible. It is often expected of an HL7 integration engine that non-standard compliant data be accepted and processed without notification to the receiving system of non-compliance.
However, to achieve real interoperability, the HL7 standard should be constrained to reduce the degree of freedom e.g. how to use certain fields or whether to populate optional fields or not. This happens either based on a written specification or in addition as machine-readble conformance profile. In order to check whether HL7 messages actually conform to the defined constraints, message validation is essential.

The HAPI library already offers support for validating HL7 messages by definition of rules that check against constraints on type level, message level, and encoded message level. However, definition of these rules is rather cumbersome.
The IPF HL7 module adds support for specifying validation rules in a way that is easy to write and easy to understand. It facilitates the definition of custom validation rules by exploiting features of the Groovy language that is already used in other parts of IPF.

Validation Basics

Validation rules are defined by instantiating an implementation of the ca.uhn.hl7v2.validation.ValidationContext interface of HAPI. Then you use this context to validate messages against the contained constraints.

Validation

There are two ways to validate:

  • while parsing a message
  • as dedicated operation on an existing message

To validate together with parsing, simply configure your Parser instance with the ValidationContext. If validation fails an exception is thrown.

To validate after parsing, use the HAPI MessageValidator class. If validation fails an exception is thrown.

IPF HL7 Validation Rules

IPF provides a special ValidationContext: the org.openehealth.ipf.modules.hl7.validation.DefaultValidationContext class. It offers two benefits:

  1. It provides access to a Validation Builder that allows for definition of validation rules using a simple Domain Specific Language (DSL)
  2. It supports Validation rules that constrain their target object by evaluating Groovy closures for better flexibility.

Although it is possible to manually instantiate the Validation rule classes that come with IPF, you normally should not care and instead use the Validation builder.
Before actually specifying the validation rule, its application is restricted to one or more HL7 versions. The possibilities are shown in the code example above and are self-describing.

Now the rules can be defined by specifying constraints on

Reusing a DefaultValidationContext

If there is already an instance of DefaultValidationContext, you can simply add further rules to it:

It is also possible to reuse any ValidationContext implementation (i.e. also not IPF-based contexts) with a DefaultValidationContext.

Configuring HL7 v2 Validation

This section explains how to configure Validation Context and Validation Rules in an application based on the Spring Framework.

  1. To initialize a DefaultValidationContext from a Spring Framework ApplicationContext, you need a ValidationContextFactoryBean and one or more ValidationContextBuilder beans. Each ValidationContextBuilder will contribute to the overall set of rules being applied.
    context.xml
  2. Provide the custom ValidationContextBuilder implementation. A skeleton for such a custom builder is given in the following example:
    MyValidationContextBuilder.groovy

Primitive Type Constraints

This section shows how to define constraints on primitive HL7 data types.

Rules from the HL7 specification already available
A set of primitive types rules are already available as defined in the HL7 specification for each 2.x version. Just use org.openehealth.ipf.modules.hl7.validation.support.DefaultTypeRulesValidationContext as your ValidationContext implementation and optionally add more validation rules to it.

Primitive types have no substructure, i.e. they directly contain string values. The values are usually constrained by one or more of the following restrictions:

  • length
  • value type (e.g. whether it evaluates to a decimal or number)
  • regular expression pattern

Regular expressions can also be used to restrict length and type of the value, however, regular expressions are sometimes hard to read and understand.

A primitiveType constraint for a range of HL7 versions is defined as follows:

This enforces that all instances of type DT type must match a date pattern, where the year is mandatory and the month and the day is optional. The example uses a regular expression to specify the date pattern. Please also read about regular expressions in Groovy (http://groovy.codehaus.org/Regular+Expressions).

The Validation DSL for primitive types supports the following constraints:

Constraint type Method .type('X') Example constraints...
maximum length .maxSize(int) maxSize(255) ... the maximum length to 255 characters
length range [min..max] [10..20] ... the length to be between 10 and 20
existence .notEmpty()   ... that there must be a value of >= 1 character
matches .matches(regexp) matches(/(\d{4}) ... the value has four digits
number type .isNumber()   ... the value to be a decimal number
user defined .checkIf(Closure) checkIf {it.size()<=255 } ... the maximum length to 255 characters

The Closure syntax is the most flexible way to define constraints on a type. Internally, all other constraint methods are implemented by calling checkIf using a specific closure.
Additionally, primitive type constraints are "misused" in HAPI for trimming space characters from values. The Validation DSL supports this as well, however, it's not recommended because it unnecessarily couples validation with preprocessing.

Constraint type Method .type('X') Example function
trim .omitLeadingWhitespace()   removes leading whitespace characters
trim .omitTrailingWhitespace()   removes trailing whitespace characters

You can combine any of constraint methods to define more than one rule for a type:

Each HL7 v2.x version defines a set of primitive types; over the time the number of types have increased and/or the constraints have been modified. IPF comes with predefined validation rules that enforce these constraints. Also note that the IPF PipeParser class is preconfigured with the default type rules.

When primitive type rules are checked
Note that primitive type rules can only be applied by configuring the parser. Validation then is executed whenever a primitive value is set:
  • during parsing
  • when individual fields are modified afterwards, e.g. by while using a transmogrifier.

Composite Type Constraints

In some technical documents there are explicit constraints on ca.uhn.hl7v2.model.Composite types. This section shows how to define validation constraints on such types.
With the composite type constraints you can validate each and every Composite instance of a given type in a HL7v2 message. For example the IHE Patient Care Device (PCD) Technical Framework 5 Volume 2 defines constraints for the XPN datatype, according to which XPN-7 (Name Type Code) is required. The following snippet configures the validation context to apply a XPNRule that checks this constrait on validation:

Here is the code for the XPNRule composite rule:

If the 7-th component of XPN (Name Type Code) is empty for some instance of the XPN type in the message, the mustBeNonEmpty method will add a ValidationException to the list of violations. That exception will will also include the path to the XPN instance that violates the constraint.

Message Constraints

This section explains how complete HL7 messages can be validated.

By default, the HAPI parsers accept about any message as long as it follows the HL7 syntactic rules. For messages, groups and segments not defined in the respective HL7 2.x standard, generic structures are internally instantiated. This allows parsing custom messages even without prior definition of Z segments or similar custom structures.
Because the parser itself can not guarantee specification-compliant messages, this has to be added either by configuring the parser or executing validation seperately.

When message validation rules are checked
Message rules can be enforced by either configuring the parser or by manually validating a parsed message.
Message rules are not enforced each time when a part of the message is modified.

There are three subtypes of message validation rules provided by IPF.

Validation Rule ValidationBuilder clause Description
HL7 Abstract Message Syntax abstractSyntax validates the existance, order, and cardinality of HL7 groups and segments
Conformance Profiles conformsToProfile validates the message against the static part of a HL7 Conformance Profile
Custom checkIf passes the Message object into as parameter into a Groovy closure, where custom validation can be executed

HL7 Abstract Message Syntax

HL7 v2 defines an Abstract Message Syntax (see HL7v2.5 specification, Chapter 2.13), that determines how groups and segments are expected for a specific message type. Cardinality is indicated by using

  • brackets ([...]) for optional groups or segments [0..1]
  • braces ({...}) for repeatable groups or segments [1..*]
  • a combination of both ({[...]} or [{...}]) for optional and repeatable groups or segments [0..*]

IPF provides support for checking a message instance against such an Abstract Message Syntax definition with the abstractSyntax builder expression. The corresponding rule is almost a copy of the definition, with only a few differences:

  • segment names are enclosed in quotes ('')
  • group names are specified like function calls inside the cardinality indicators as described above
  • a choice of one segment from a group of segments is currently not supported.

The following comparison gives an example:

HL7 Abstract Message Syntax definition IPF Validation rule

Note that fields inside segments can neither be specified nor validated with the Abstract Message Syntax.

HL7 Conformance Profiles

Conformance Profiles have been introduced with HL7 v2.5 as a standardized means of defining the static and dynamic properties of a HL7 message. Conformance Profiles are encoded in XML and can be seen as a formal specification language. For more details on HL7 Conformance Profiles, please refer to chapters 2.12 and 2.19 of the HL7 v2.5 specification document.
There are tools that facilitate the definition of Conformance Profiles, most notably the Messaging Workbench, which can be downloaded at http://sl.infoway-inforoute.ca/downloads/MWB%20Release%206-7p1.zip.

HAPI supports checks against conformance profiles. In the IPF Validation framework it can be used with the conformsToProfile builder expression.

In this case, a file with the name IHE-PDQ-QBP-Q22.xml is looked up in the root of the Java classpath. Without the call to ProfileStoreFactory.setStore, the default HAPI ProfileStore is used, which looks into the <hapi.home>/profiles directory.

Custom Message Validation

You can use message rules also to program you own custom constraints on one or more trigger events. All there is to do is to write a checkIf closure that returns an array of HAPI {{ValidationException}}s. The array is empty, if validation passes.

Encoded Message Constraints

These kind of rules can be used to validate the encoded representation of a HL7 message, i.e. their String representation in either ER7 (Pipe) or XML encoding. Besides providing a ClosureEncodingRule class, only a link to HAPI's XMLSchemaRule is defined:

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.