| 1 | MAG7UP ;WOIFO/MLH - Imaging - HL7 - utilities - break out message into a parse tree ; 06/03/2005  12:05
 | 
|---|
| 2 |  ;;3.0;IMAGING;**11,51**;26-August-2005
 | 
|---|
| 3 |  ;; +---------------------------------------------------------------+
 | 
|---|
| 4 |  ;; | Property of the US Government.                                |
 | 
|---|
| 5 |  ;; | No permission to copy or redistribute this software is given. |
 | 
|---|
| 6 |  ;; | Use of unreleased versions of this software requires the user |
 | 
|---|
| 7 |  ;; | to execute a written test agreement with the VistA Imaging    |
 | 
|---|
| 8 |  ;; | Development Office of the Department of Veterans Affairs,     |
 | 
|---|
| 9 |  ;; | telephone (301) 734-0100.                                     |
 | 
|---|
| 10 |  ;; |                                                               |
 | 
|---|
| 11 |  ;; | The Food and Drug Administration classifies this software as  |
 | 
|---|
| 12 |  ;; | a medical device.  As such, it may not be changed in any way. |
 | 
|---|
| 13 |  ;; | Modifications to this software may result in an adulterated   |
 | 
|---|
| 14 |  ;; | medical device under 21CFR820, the use of which is considered |
 | 
|---|
| 15 |  ;; | to be a violation of US Federal Statutes.                     |
 | 
|---|
| 16 |  ;; +---------------------------------------------------------------+
 | 
|---|
| 17 |  ;;
 | 
|---|
| 18 |  Q
 | 
|---|
| 19 |  ;
 | 
|---|
| 20 | PARSE(XMSG,XTREE) ; break the HL7 message lines into a parse tree
 | 
|---|
| 21 |  ;
 | 
|---|
| 22 |  ; INPUT:  The single-dimensional array of message lines
 | 
|---|
| 23 |  ;
 | 
|---|
| 24 |  ; OUTPUT:  The parse tree, in the structure
 | 
|---|
| 25 |  ;   @XTREE@(NSEG,0)                    segment name
 | 
|---|
| 26 |  ;   @XTREE@(NSEG,NFLD,NREP,NCMP,NSCM)  element data
 | 
|---|
| 27 |  ;   @XTREE@("B",SEGID,NSEG)          null
 | 
|---|
| 28 |  ;
 | 
|---|
| 29 |  N I,J,K,L,M,X,Z ; --------------------- scratch vars
 | 
|---|
| 30 |  N IMSG ; ------------------------------ message array index
 | 
|---|
| 31 |  N ISUBSEG ; --------------------------- index of continuation data for long segs
 | 
|---|
| 32 |  N ISUCC ; ----------------------------- successor element index
 | 
|---|
| 33 |  N FERR ; ------------------------------ error flag
 | 
|---|
| 34 |  N SEG ; ------------------------------- segment data
 | 
|---|
| 35 |  N SEGTAG ; ---------------------------- segment ID ("0th" piece)
 | 
|---|
| 36 |  N UFS,UCS,URS,UEC,USS ;---------------- HL7 delimiters (universal)
 | 
|---|
| 37 |  N ENC ;-------------------------------- HL7 encoding characters
 | 
|---|
| 38 |  N UFSESC,UCSESC,URSESC,UECESC,USSESC ;- HL7 escape sequences for delimiters (universal)
 | 
|---|
| 39 |  N PATTERN ; --------------------------- pattern match for spanned record
 | 
|---|
| 40 |  N NSEG ; ------------------------------ segment number in the parse tree
 | 
|---|
| 41 |  N NSEGINPT ; -------------------------- segment number of input HL7 data
 | 
|---|
| 42 |  N NFLD ; ------------------------------ field number in the segment
 | 
|---|
| 43 |  N FLD ; ------------------------------- field data
 | 
|---|
| 44 |  ;
 | 
|---|
| 45 |  S FERR=0 ; assume no error
 | 
|---|
| 46 |  S IMSG=""
 | 
|---|
| 47 |  ;
 | 
|---|
| 48 |  ; process MSH segment
 | 
|---|
| 49 |  ; If there's a message problem, return it in an NTE segment.
 | 
|---|
| 50 |  ;
 | 
|---|
| 51 |  S IMSG=$O(@XMSG@(IMSG)) ; array sent?
 | 
|---|
| 52 |  I IMSG="" D  Q FERR ; no
 | 
|---|
| 53 |  . S FERR=-1
 | 
|---|
| 54 |  . ; have to use default field separator
 | 
|---|
| 55 |  . S @XMSG@(0)="NTE|1||"_FERR_";no input array found"
 | 
|---|
| 56 |  . Q
 | 
|---|
| 57 |  S SEG=$G(@XMSG@(IMSG)) Q:$E(SEG,1,3)'="MSH" -2 ; an HL7 message?
 | 
|---|
| 58 |  I $E(SEG,1,3)'="MSH" D  Q FERR ; no
 | 
|---|
| 59 |  . S FERR=-2
 | 
|---|
| 60 |  . S ISUCC=$O(@XMSG@(IMSG)) S:'ISUCC ISUCC=IMSG+1
 | 
|---|
| 61 |  . ; have to use default field separator
 | 
|---|
| 62 |  . S @XMSG@(IMSG+ISUCC/2)="NTE|1||"_FERR_";invalid HL7 message (1st 3 chars must be MSH)"
 | 
|---|
| 63 |  . Q
 | 
|---|
| 64 |  ;
 | 
|---|
| 65 |  ; set up delimiters and escape sequences
 | 
|---|
| 66 |  S UFS=$E(SEG,4),@XTREE@(1,1,1,1,1)=UFS
 | 
|---|
| 67 |  S ENC=$P(SEG,UFS,2),@XTREE@(1,2,1,1,1)=ENC
 | 
|---|
| 68 |  S UCS=$E(ENC),URS=$E(ENC,2),UEC=$E(ENC,3),USS=$E(ENC,4)
 | 
|---|
| 69 |  S UFSESC=UEC_"F"_UEC,UCSESC=UEC_"S"_UEC,URSESC=UEC_"S"_UEC,UECESC=UEC_"E"_UEC,USSESC=UEC_"T"_UEC
 | 
|---|
| 70 |  S PATTERN="1A2AN1"""_UFS_""""
 | 
|---|
| 71 |  S @XTREE@(1,0)="MSH",@XTREE@("B","MSH",1)=""
 | 
|---|
| 72 |  F NFLD=3:1:$L(SEG,UFS) S FLD=$P(SEG,UFS,NFLD) D
 | 
|---|
| 73 |  . I FLD]"" D PROCFLD(XTREE,1,NFLD,FLD)
 | 
|---|
| 74 |  . Q
 | 
|---|
| 75 |  ; process the remaining segments
 | 
|---|
| 76 |  S SEG="" ; SEG will be a concatenated series of spanned records
 | 
|---|
| 77 |  S NSEG=2 ; next segment in the parse tree will be #2
 | 
|---|
| 78 |  F NSEGINPT=2:1 S IMSG=$O(@XMSG@(IMSG)) Q:IMSG=""  D  Q:FERR
 | 
|---|
| 79 |  . S SEG=$G(@XMSG@(IMSG)) Q:SEG=""
 | 
|---|
| 80 |  . S ISUBSEG="" ; prepare to handle very long HL7 segments (up to 32K)
 | 
|---|
| 81 |  . F  S ISUBSEG=$O(@XMSG@(IMSG,ISUBSEG)) Q:ISUBSEG=""  D
 | 
|---|
| 82 |  . . S SEG=SEG_$G(@XMSG@(IMSG,ISUBSEG))
 | 
|---|
| 83 |  . . Q
 | 
|---|
| 84 |  . S SEGTAG=$P(SEG,UFS) I SEGTAG'?1U2.3UN S FERR=-3 Q
 | 
|---|
| 85 |  . S @XTREE@(NSEG,0)=SEGTAG,@XTREE@("B",SEGTAG,NSEG)=""
 | 
|---|
| 86 |  . F NFLD=2:1:$L(SEG,UFS) D
 | 
|---|
| 87 |  . . S FLD=$P(SEG,UFS,NFLD)
 | 
|---|
| 88 |  . . I FLD]"" D PROCFLD(XTREE,NSEG,NFLD-1,FLD)
 | 
|---|
| 89 |  . . Q
 | 
|---|
| 90 |  . S SEG="" ; reinitialize SEG for the next possible concatenation
 | 
|---|
| 91 |  . S NSEG=NSEG+1 ; increment counter for next segment in the parse tree
 | 
|---|
| 92 |  . Q
 | 
|---|
| 93 |  Q FERR
 | 
|---|
| 94 |  ;
 | 
|---|
| 95 | PROCFLD(XTREE,XNSEG,XNFLD,XFLD) ; process a field
 | 
|---|
| 96 |  ;
 | 
|---|
| 97 |  ; input:  XTREE   name of MUMPS array for parse tree ($NA format)
 | 
|---|
| 98 |  ;         XNSEG   segment number for parse tree
 | 
|---|
| 99 |  ;         XNFLD   field number for parse tree
 | 
|---|
| 100 |  ;         XFLD    field data
 | 
|---|
| 101 |  ;
 | 
|---|
| 102 |  N SG ; ------ segment name
 | 
|---|
| 103 |  N NREP ; ---- repetition (occurrence) number
 | 
|---|
| 104 |  N REP ; ----- repetition data
 | 
|---|
| 105 |  N NCMP ; ---- component number
 | 
|---|
| 106 |  N CMP ; ----- component data
 | 
|---|
| 107 |  N NSCM ; ---- subcomponent number
 | 
|---|
| 108 |  N SCM ; ----- subcomponent data
 | 
|---|
| 109 |  ;
 | 
|---|
| 110 |  S SG=@XTREE@(XNSEG,0)
 | 
|---|
| 111 |  ; Per DICOM meeting 2004-02-24, reaffirmed that data may need to be
 | 
|---|
| 112 |  ; retrieved above the subcomponent level, and that those data will
 | 
|---|
| 113 |  ; need to be de-escaped because the receiving application won't have
 | 
|---|
| 114 |  ; access to the delimiters from the original message.
 | 
|---|
| 115 |  S @XTREE@(XNSEG,XNFLD)=$$DEESC(XFLD)
 | 
|---|
| 116 |  ;
 | 
|---|
| 117 |  ; Break out to the lowest delimiter level too.  This is not strictly an
 | 
|---|
| 118 |  ; HL7 parse because it does not take actual HL7 (or realm constraining)
 | 
|---|
| 119 |  ; data types into account.
 | 
|---|
| 120 |  ;
 | 
|---|
| 121 |  F NREP=1:1:$L(XFLD,URS) S REP=$P(XFLD,URS,NREP) I REP]"" D
 | 
|---|
| 122 |  . F NCMP=1:1:$L(REP,UCS) S CMP=$P(REP,UCS,NCMP) I CMP]"" D
 | 
|---|
| 123 |  . . ; Per DICOM meeting 2004-02-24, reaffirmed that data may need to be
 | 
|---|
| 124 |  . . ; retrieved above the subcomponent level, and that those data will
 | 
|---|
| 125 |  . . ; need to be de-escaped because the receiving application won't have
 | 
|---|
| 126 |  . . ; access to the delimiters from the original message.
 | 
|---|
| 127 |  . . S @XTREE@(XNSEG,XNFLD,NREP,NCMP)=$$DEESC(CMP)
 | 
|---|
| 128 |  . . F NSCM=1:1:$L(CMP,USS) S SCM=$P(CMP,USS,NSCM) I SCM]"" D
 | 
|---|
| 129 |  . . . S @XTREE@(XNSEG,XNFLD,NREP,NCMP,NSCM)=$$DEESC(SCM)
 | 
|---|
| 130 |  . . . Q
 | 
|---|
| 131 |  . . Q
 | 
|---|
| 132 |  . Q
 | 
|---|
| 133 |  Q
 | 
|---|
| 134 |  ;
 | 
|---|
| 135 | DEESC(XSCM) ; replace escape sequences with delimiter characters
 | 
|---|
| 136 |  ;
 | 
|---|
| 137 |  ; input:  XSCM   element data before replacement
 | 
|---|
| 138 |  ;
 | 
|---|
| 139 |  ; expects:  UFSESC, UCSESC, URSESC, UECESC, USSESC
 | 
|---|
| 140 |  ;                delimiter escape sequences
 | 
|---|
| 141 |  ;
 | 
|---|
| 142 |  ; function return:  element data after replacement
 | 
|---|
| 143 |  ;
 | 
|---|
| 144 |  N HIT ; need another pass after each hit
 | 
|---|
| 145 |  F  D  Q:'$D(HIT)
 | 
|---|
| 146 |  . K HIT
 | 
|---|
| 147 |  . I XSCM[UFSESC S XSCM=$P(XSCM,UFSESC)_UFS_$P(XSCM,UFSESC,2,99999),HIT=1
 | 
|---|
| 148 |  . I XSCM[UCSESC S XSCM=$P(XSCM,UCSESC)_UCS_$P(XSCM,UCSESC,2,99999),HIT=1
 | 
|---|
| 149 |  . I XSCM[URSESC S XSCM=$P(XSCM,URSESC)_URS_$P(XSCM,URSESC,2,99999),HIT=1
 | 
|---|
| 150 |  . I XSCM[UECESC S XSCM=$P(XSCM,UECESC)_UEC_$P(XSCM,UECESC,2,99999),HIT=1
 | 
|---|
| 151 |  . I XSCM[USSESC S XSCM=$P(XSCM,USSESC)_USS_$P(XSCM,USSESC,2,99999),HIT=1
 | 
|---|
| 152 |  . Q
 | 
|---|
| 153 |  Q $E(XSCM,1,510)
 | 
|---|
| 154 |  ;
 | 
|---|