\documentstyle[germanb,umlaut,dina4,epsf,twoside,twocolumn]{article}
%\documentclass[twoside,twocolumn]{article}
%\usepackage[latin1]{inputenc}
%\usepackage{german}
%\usepackage{epsf}
%\usepackage{a4}
%\usepackage{floatflt}
%\usepackage{multicol}
\def\epsfsize#1#2{0.5#1} %\epsfverbosetrue
\def\epsffile#1#2{\vbox{\null\vskip15pt
	\centerline{\epsfbox{#1}}%
	\vskip10pt
	\centerline{#2}
	\vskip15pt}}%
\title{ProtoGen/HL7 --- eine C++ Klassenbibliothek für HL7}
\author{Gunther Schadow\thanks{schadow@ukbf.fu-berlin.de}}
\date{\today}
\begin{document}
\maketitle
\begin{abstract}
Mit dem Programmgenerator ProtoGen/HL7\footnote{ProtoGen/HL7
ist freie Software. Bezug über WWW:\linebreak
http://fub46.zedat.fu-berlin.de:8080/{\lower0.75ex\hbox{\char"7E}}gusw/
oder FTP:\linebreak
dumccss.mc.duke.edu:standards/HL7/implementations}
wurde der HL7 Standard in Form einer C++ Klassenbibliothek
vollständig implementiert. Dies erlaubt die schnelle Ausrüstung von
Anwendungen mit einer HL7 Schnittstelle.  Ergänzungen zum HL7
Standard können schnell und effizient integriert werden.  Weiter
lassen sich einerseits andere HL7 Schnittstellen auf Korrektheit
untersuchen und andererseits der HL7 Standard selbst auf
Vollständigkeit und Widerspruchsfreiheit.
\end{abstract}
%\multicols{2}
\section{Der Kontext}
Mein Projektziel im Rahmen meiner Doktorarbeit, die ich im Herbst 1993
am Universitätsklinikum Benjamin Franklin begann, lautet, einen HL7
basierten klinikweiten Kommunikationsdienst zu entwickeln.

Die EDV Umgebung bietet, was die Hardware- und Betriebsystem-Ebene
betrifft, mit lei\-stungs\-fä\-higen Unix Work\-stations an einem schnellen
LAN, auf welchem die Internet-Protokolle gefahren werden, sehr gute
Voraussetzungen. Die Ausstattung mit hochwertiger klinischer Software,
die den Anforderungen an offene Systeme entspricht, ist dagegen eher
beschränkt: Ein proprietäres KIS und eine selbst entwickelte
DOS/dBase Patientendatenbank auf der anaesthesiologischen Abteilung,
ein proprietäres RIS in der radiologischen Abteilung, ein
proprietäres Stammdatensystem und einige PC Inselapplikationen.
Einzig das KIS der Anaesthesiologie weist eine bescheidene HL7
Schnittstelle auf.

Jedenfalls wurde zunächst eine mög\-lichst voll\-stän\-di\-ge HL7
Implementation gebraucht. Da keine geeignete fertige Software zur
Verfügung stand, mußte schließlich selbst eine erstellt werden.

\section{Die Methode}
Der große Umfang des HL7 Standards erfordert eine weitgehend
automatisierte Methode, um in angemessener Zeit eine zuverlässige
Implementation zu erstellen, die sowohl an lokale Gegenbenheiten
anpassungsfähig, als auch für spätere Versionen von HL7 weiter
verwendbar bleiben soll.

Mir lag die deutsche Edition der HL7 Version 2.1 in Form von Word 5.0
Dateien vor, die abgesehen von binären Formatköpfen und -Anhängen,
ASCII texte sind. Damit konnte ich mit den üblichen Unix-Werkzeugen
"`sed"' und "`awk"' die formalisierten Informationen, wie Nachrichten-
und Segment-Definitionen, sowie Code-Tabellen extrahieren. Zur
Weiterverarbeitung wurden die gewonnenen Informationen in Prolog
Syntax gebracht. Die programmiersprache Prolog eignet sich besonders
gut, um Annahmen an der Wissensbasis zu beweisen. Dies waren zunächst
Konsistenzprüfungen.

Dabei stellte sich heraus, daß der HL7 Standard in jener Version
viele Mängel hinsichtlich der Konsistenz und Vollständigkeit
aufwies. Dies reichte von undefinierteten Nachrichten und Segmenten,
über fehlende, als "`HL7-Standard"' deklarierte Code-Tabellen, bis zu
Syntax-Fehlern in den Nachrichtendefinitionen. Nicht alle dieser
Fehler ließen sich mit Hilfe des narrativen, den automatischen
Methoden zunächst unzugänglichen Teils des Textes korrigieren.
Manches mußte improvisiert werden, und nicht alle dieser
Improvisationen erwiesen sich später als richtig.

Nachdem die HL7 Wissensbasis manuell in einen weitgehend konsistenten
Zustand gebracht wurde, konnte in einem zweiten Schritt ein
Programmgenerator geschrieben werden, welcher den eigentlichen
Quellcode der HL7 Implementation produzieren sollte.  Vorbilder zu
diesem Vorhaben waren ähnliche Generatoren, wie sie in Sun-RPC
("`rpcgen"') und ISO/OSI Um\-ge\-bun\-gen (ASN.1 Com\-piler) be\-nutzt
wer\-den.

\section{Anforderungen}
Die HL7 Implementation sollte folgenden allgemeinen Anforderungen genügen:
\begin{itemize}
\item
in einer Objektbibliothek für bestehende und zukünftige Anwendungen
verfügbar sein

\item
in einer verbreiteten, unabhängigen Programmiersprache geschrieben sein

\item
die HL7-Konzepte (Message, Segment etc.) möglichst klar und direkt
wiedergeben

\item
in der Anwendung so einfach wie möglich und dennoch ausdrucksstark
sein

\item
das OSI-Referenzmodell beachten, insbesondere die Schichtung nicht
verletzen, bzw. dort zu kompensieren wo HL7 diese Schichtung verletzt.
\end{itemize}

Nachdem ich die ersten Ansätze in der Programmiersprache C geplant
hatte wurde bald deutlich, daß insbesondere das Ziel der Einfachheit
und Klarheit nur mit den objekt-orientierten Erweiterungen zu
erreichen waren, wie sie C++ bietet. Hiermit ist es möglich, selbst
komplizierte Aspekte der Implementation einiger Module, vom
Anwendungsprogrammierer fern zu halten. Dieser kann beispielsweise ein
wiederholbares Feld wie ein Array behandeln, obwohl dem eigentlich
eine verkettete Liste zugrunde liegt. Er braucht sich nicht um
dynamischen Speicher zu kümmern. Zeichenketten, selbst ganze Segmente
und Nachrichten können wie atomare Werte behandelt werden.

Der Anwendungsprogrammierer darf sich selbstverständlich nicht darum
sorgen müssen, daß gewisse Zeichen, die er in einem Textdatum
verwendet, mit den Trenn- oder Steuerzeichen irgendwelcher tieferer
Protokollschichten interferieren könnten. Diese Dinge bleiben vor ihm
verborgen, wie es das OSI Schichtenmodell fordert.

\section{Grundfunktionen}
Realisiert wurden zunächst die folgenden Dienste, die vor allem in
der Präsentations-Schicht (6) nach dem OSI-Referenzmodell liegen:

\begin{enumerate}
\item
Datenstrukturen als Schnittstelle zur An\-wen\-dungs-Schicht (7)

\item
eine Funktion, die die Datenstrukturen mittels der HL7 Codierregeln
serialisiert ("`builder"').

\item
eine Funktion, die einen serialisierten HL7 Zeichenstrom analysiert
und die Datenstrukturen entsprechend aufbaut ("`parser"').

\end{enumerate}

Abbildung 1 gibt einen Überblick über die Struktur der HL7 Klassen.
Aus Platzgründen sind nur die abstrakten Klassen aufgeführt,
während sich die konkreten jeweils von ihrer abstrakten Klasse
ableiten. So ist zum Beispiel das MSH-Segment von der Klasse
"`Segment"' und der DT-Datentyp von der Klasse "`Primtype"'
abgeleitet.

%\begin{floatingfigure}{9cm}
\begin{figure}[h]
\epsffile{objtree.eps}{Abb. 1: ProtoGen/HL7 Klassenhierarchie}
\end{figure}
%\end{floatingfigure}

Die Datenstrukturen (C++ Klassen) gestatten wahlfreier Zugriff
auf die Inhalte der Nachrichten, wobei die Reihenfolge der Felder
nicht beachtet werden muß. Die Bezeichner werden mit einem einfachen
Algorithmus aus den standard Datenelementnamen gebildet, wodurch sie
kurz und dennoch lesbar bleiben. Man kann z.B. auf den Patientennamen
in einer ADT-Nachricht {\tt msg} symbolisch einfach so zugreifen:
\begin{verbatim}
msg.PatIde.PatName.FamName = "Meier";
\end{verbatim}
%
% The following paragraph is a bit hard to break:
%
Jede Klasse besitzt eine Reihe von Funktionen\break
(Methoden), von denen ich hier nur die Ein- und\break
Ausgabe-Funktionen nennen will. Diese lesen von,\break
bzw. schreiben auf eine Zeichenstrom-Abstraktion,\break
wie sie mit der standard "`IOstream"' Bibliothek\break
zur Verfügung stehen.  Diese Ströme können beliebig mit einem
konkreten Ein-/Ausgabegerät verbunden werden, wie einer Datei, einem
TCP/IP Socket, einer serielle Schnittstelle u.dgl. Die anderen
\pagebreak Methoden sind vor allem am Management der Objekte
beteiligt. Abbildung 2 zeigt beispielhaft die Deklaration des
NK1-Segmentes.
\nopagebreak
%\begin{floatingfigure}{9cm}
\begin{figure}[h]
{\small
\begin{verbatim}
class NK1seg : public Segment
{
 public:
  SItyp           SetIdNextOfKin;
  PNtyp           NextOfKinName;
  STtyp           NextOfKinRel;
  ADtyp           NextOfKinAdd;
  repfield<TNtyp> NextOfKinPhoneNum;
  
  NK1seg();
  
  result input(istream&);
  void   output(ostream&) const;
};
\end{verbatim}}
\centerline{Abb. 2: Deklaration der NK1 Segment-Klasse}
\end{figure}
%\end{floatingfigure}

Das Konzept von ProtoGen/HL7 ist nicht auf HL7 beschränkt. Mit
relativ geringem Aufwand können auch HL7 ähnliche Standards
(EDIFACT, ANSI X12, ASTM) integriert werden. Durch den
objekt-orientierten Aufbau können auch ganz andere Codierungsregeln
verwendet werden, wie sie zum Beispiel bei DICOM Verwendung finden.

\section{Praktische Anwendung}
Mit der so erstellten Bibliothek waren HL7 Testanwendungen in sehr
kurzer Zeit zu erstellen. Dies sind: eine Schnittstelle zu einer
Oracle Patientendatenbank und ein Gateway zu dem oben genannten
proprietären KIS. Eine Schnittstelle zu einem Labor-Roboter wird in
nächster Zeit erstellt und weitere Schnittstellen, wie zur Radiologie
oder Mikrobiologie, sind geplant. Besonders bei der Anbindung des KIS,
dessen HL7 Schnittstelle Z-Segmente gebraucht, machte sich die
flexibilität meiner Methode bezahlt: Die Abweichungen vom HL7
Standard waren binnen einer halben Stunde gebrauchsfertig
implementiert.

Bei jedem der Entwicklungsschritte treten je eigene Probleme auf, die
mit HL7 zusammenhängen. Waren es bei der Implementaion des Standards
selbst nur die formalen Inkonsistenzen, so wird bei der Entwicklung
von Anwendungen die Unvollständigkeit und nur vage Bestimmtheit von
HL7 zum überragenden Problem. Fragen wie die nach dem Unterschied
zwischen "`patient type"', "`patient class"' und "`admission type"'
sind anhand des offiziellen Standards ebenso wenig zu klären wie die,
wie man die Information über den Hausarzt konsequent und vollständig
unterbringen kann. Fehlende Codetabellen tun ihr übriges, um
Interoperabilität mit HL7 zu erschweren.

\section{Ähnliche Arbeiten}

Seit dem Beginn der Arbeiten an ProtoGen/HL7 wurden auch andere
HL7 Implementationen bekannt. "`HL7ImExa"'\footnote{Allen Rueter
$<$allen@mir.wustl.edu$>$} ist eine vergleichsweise 
einfache Implementation, bestehend aus einigen C-Funktionen, die desto
schwieriger in der Anwendung ist.  Sie bietet keine Datenstrukturen,
und ist nicht typensicher\footnote{d.h. man kann versehentlich eine
Aufnahmenummer als Geburtsdatum interpretieren.}, geschweige denn
objekt-orientiert.

Eine andere Implementation in C++\footnote{S. Munjal, et.al.: A
C++Class Library for DICOM and HL-7, Proceedings of CAR '95, Berlin
1995, Springer-Verlag} deckt nur eine Untermenge von HL7 ab, nämlich
die Schnittmenge mit DICOM. Der Code ist manuell erzeugt und daher
wenig flexibel. Obwohl C++ benutzt wird, ist die
Programmierschittstelle weniger Komfortabel und nicht typensicher, da
ebenfalls alle Daten als Strings behandelt werden.
 
\section{Ausblick}
Noch ausstehende Arbeiten an der HL7 Bibliothek sind neben der
Aufnahme von Version 2.2 vor allem Unterstützung in den
Netzwerkfunktionen, um auf alle möglichen Übertragungsmedien in
gleicher Weise zugreifen zu können ({\tt connect()}, {\tt accept()}
etc.).

Des weiteren arbeite ich daran, die Bibliothek um eine Remote
procedure call (RPC) Semantik zu erweitern.  Damit soll es möglich
sein, von den Nachrichten selbst zu abstrahieren, und nur noch mit
Informationen und Aktionen zu handeln. So soll der
Anwendungsprogrammierer von der Aufgabe befreit werden, die richtige
ACK Nachricht auf eine Message zu empfangen (bzw. zu senden), zu
prüfen, und auf eventuelle Fehler zu reagieren. Um Antwortnachrichten
sollte er sich nur kümmern müssen, sofern sie angeforderte
Informationen enthalten. Damit ist auch ein Weg vorgezeichnet, wie
über die Implementation von statischen Datenmodellen hinaus auch
dynamische, operationale Aspekte des HL7 Standards formal erfaßt und
zuverlässig implementiert werden können.
\end{document}
