source: ccr/trunk/p/C0CMXML.m@ 605

Last change on this file since 605 was 605, checked in by George Lilly, 14 years ago

CCD import processing

File size: 11.8 KB
Line 
1C0CMXML ; ERX/GPL - MXML based XPath utilities;10/13/09 17:05
2 ;;0.1;C0P;nopatch;noreleasedate
3 ;Copyright 2009 George Lilly. Licensed under the terms of the GNU
4 ;General Public License See attached copy of the License.
5 ;
6 ;This program is free software; you can redistribute it and/or modify
7 ;it under the terms of the GNU General Public License as published by
8 ;the Free Software Foundation; either version 2 of the License, or
9 ;(at your option) any later version.
10 ;
11 ;This program is distributed in the hope that it will be useful,
12 ;but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ;GNU General Public License for more details.
15 ;
16 ;You should have received a copy of the GNU General Public License along
17 ;with this program; if not, write to the Free Software Foundation, Inc.,
18 ;51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ;
20 Q
21 ;
22TEST ;
23 S C0CXMLIN=$NA(^TMP("C0CMXML",$J))
24 K GARY
25 W $$FTG^%ZISH("/home/vademo2/EHR/p/","mxml-test.xml",$NA(@C0CXMLIN@(1)),3)
26 S C0CDOCID=$$PARSE(C0CXMLIN) W !,"DocID: ",C0CDOCID
27 S REDUX="//ContinuityOfCareRecord/Body"
28 D XPATH(1,"/","GIDX","GARY",,REDUX)
29 Q
30 ;
31TEST2 ;
32 S REDUX="//soap:Envelope/soap:Body/GetPatientFullMedicationHistory5Response/GetPatientFullMedicationHistory5Result/patientDrugDetail"
33 D XPATH(1,"/","GIDX","GARY","",REDUX)
34 Q
35 ;
36TEST3
37 S C0CXMLIN=$NA(^TMP("C0CMXML",$J))
38 K GARY,GTMP,GIDX
39 K @C0CXMLIN
40 W $$FTG^%ZISH("/home/vademo2/CCR/","SampleCCDDocument.xml",$NA(@C0CXMLIN@(1)),3)
41 D CLEANARY("GTMP",C0CXMLIN) ; REMOVE CONTROL CHARACTERS
42 K @C0CXMLIN
43 M @C0CXMLIN=GTMP
44 K GTMP
45 D STRIPTXT("GTMP",C0CXMLIN)
46 K @C0CXMLIN
47 M @C0CXMLIN=GTMP
48 K GTMP
49 S C0CDOCID=$$PARSCCD(C0CXMLIN,"W") W !,"DocID: ",C0CDOCID
50 S REDUX="//ClinicalDocument/component/structuredBody"
51 D FINDTID ; FIND THE TEMPLATE IDS
52 D FINDALT ; FIND ALTERNATE TAGS
53 D SETCBK ; SET THE CALLBACK ROUTINE FOR TAGS
54 D XPATH(1,"/","GIDX","GARY",,REDUX)
55 D SEPARATE("GARY2","GARY") ; SEPARATE FOR EASIER BROWSING
56 ;S C0CDOCID=$$PARSE(C0CXMLIN) W !,"DOCID: ",C0CDOCID ;CALL REGULAR PARSER
57 ;D XPATH(1,"/","GIDX2","GARY2",,REDUX)
58 Q
59 ;
60XPATH(ZOID,ZPATH,ZXIDX,ZXPARY,ZNUM,ZREDUX) ; RECURSIVE ROUTINE TO POPULATE
61 ; THE XPATH INDEX ZXIDX, PASSED BY NAME
62 ; THE XPATH ARRAY XPARY, PASSED BY NAME
63 ; ZOID IS THE STARTING OID
64 ; ZPATH IS THE STARTING XPATH, USUALLY "/"
65 ; ZNUM IS THE MULTIPLE NUMBER [x], USUALLY NULL WHEN ON THE TOP NODE
66 ; ZREDUX IS THE XPATH REDUCTION STRING, TAKEN OUT OF EACH XPATH IF PRESENT
67 I $G(ZREDUX)="" S ZREDUX=""
68 N NEWPATH
69 N NEWNUM S NEWNUM=""
70 I $G(ZNUM)>0 S NEWNUM="["_ZNUM_"]"
71 S NEWPATH=ZPATH_"/"_$$TAG(ZOID)_NEWNUM ; CREATE THE XPATH FOR THIS NODE
72 I $G(ZREDUX)'="" D ; REDUX PROVIDED?
73 . N GT S GT=$P(NEWPATH,ZREDUX,2)
74 . I GT'="" S NEWPATH=GT
75 S @ZXIDX@(NEWPATH)=ZOID ; ADD THE XPATH FOR THIS NODE TO THE XPATH INDEX
76 N GD D DATA("GD",ZOID) ; SEE IF THERE IS DATA FOR THIS NODE
77 I $D(GD(2)) M @ZXPARY@(NEWPATH)=GD ; IF MULITPLE DATA MERGE TO THE ARRAY
78 E I $D(GD(1)) S @ZXPARY@(NEWPATH)=GD(1) ; IF SINGLE VALUE, ADD TO ARRAY
79 N ZFRST S ZFRST=$$FIRST(ZOID) ; SET FIRST CHILD
80 I ZFRST'=0 D ; THERE IS A CHILD
81 . N ZNUM
82 . N ZMULT S ZMULT=$$ISMULT(ZFRST) ; IS FIRST CHILD A MULTIPLE
83 . D XPATH(ZFRST,NEWPATH,ZXIDX,ZXPARY,$S(ZMULT:1,1:""),ZREDUX) ; DO THE CHILD
84 N GNXT S GNXT=$$NXTSIB(ZOID)
85 I $$TAG(GNXT)'=$$TAG(ZOID) S ZNUM="" ; RESET COUNTING AFTER MULTIPLES
86 I GNXT'=0 D ;
87 . N ZMULT S ZMULT=$$ISMULT(GNXT) ; IS THE SIBLING A MULTIPLE?
88 . I (ZNUM="")&(ZMULT) D ; SIBLING IS FIRST OF MULTIPLES
89 . . N ZNUM S ZNUM=1 ;
90 . . D XPATH(GNXT,ZPATH,ZXIDX,ZXPARY,ZNUM,ZREDUX) ; DO NEXT SIB
91 . E D XPATH(GNXT,ZPATH,ZXIDX,ZXPARY,$S(ZNUM>0:ZNUM+1,1:""),ZREDUX) ; DO NEXT SIB
92 Q
93 ;
94PARSE(INXML,INDOC) ;CALL THE MXML PARSER ON INXML, PASSED BY NAME
95 ; INDOC IS PASSED AS THE DOCUMENT NAME - DON'T KNOW WHERE TO STORE THIS NOW
96 ; EXTRINSIC WHICH RETURNS THE DOCID ASSIGNED BY MXML
97 ;Q $$EN^MXMLDOM(INXML)
98 Q $$EN^MXMLDOM(INXML,"W")
99 ;
100ISMULT(ZOID) ; RETURN TRUE IF ZOID IS ONE OF A MULTIPLE
101 N ZN
102 ;I $$TAG(ZOID)["entry" B
103 S ZN=$$NXTSIB(ZOID)
104 I ZN'="" Q $$TAG(ZOID)=$$TAG(ZN) ; IF TAG IS THE SAME AS NEXT SIB TAG
105 Q 0
106 ;
107FIRST(ZOID) ;RETURNS THE OID OF THE FIRST CHILD OF ZOID
108 Q $$CHILD^MXMLDOM(C0CDOCID,ZOID)
109 ;
110PARENT(ZOID) ;RETURNS THE OID OF THE PARENT OF ZOID
111 Q $$PARENT^MXMLDOM(C0CDOCID,ZOID)
112 ;
113TAG(ZOID) ; RETURNS THE XML TAG FOR THE NODE
114 ;I ZOID=149 B ;GPLTEST
115 N X,Y
116 S Y=""
117 S X=$G(C0CCBK("TAG")) ;IS THERE A CALLBACK FOR THIS ROUTINE
118 I X'="" X X ; EXECUTE THE CALLBACK, SHOULD SET Y
119 I Y="" S Y=$$NAME^MXMLDOM(C0CDOCID,ZOID)
120 Q Y
121 ;
122NXTSIB(ZOID) ; RETURNS THE NEXT SIBLING
123 Q $$SIBLING^MXMLDOM(C0CDOCID,ZOID)
124 ;
125DATA(ZT,ZOID) ; RETURNS DATA FOR THE NODE
126 ;N ZT,ZN S ZT=""
127 ;S C0CDOM=$NA(^TMP("MXMLDOM",$J,C0CDOCID))
128 ;Q $G(@C0CDOM@(ZOID,"T",1))
129 S ZN=$$TEXT^MXMLDOM(C0CDOCID,ZOID,ZT)
130 Q
131 ;
132PARSCCD(DOC,OPTION) ; THIS WAS COPIED FROM EN^MXMLDOM TO CUSTIMIZE FOR
133 ; PROCESSING CCDS
134 N CBK,SUCCESS,LEVEL,NODE,HANDLE
135 K ^TMP("MXMLERR",$J)
136 L +^TMP("MXMLDOM",$J):5
137 E Q 0
138 S HANDLE=$O(^TMP("MXMLDOM",$J,""),-1)+1,^(HANDLE)=""
139 L -^TMP("MXMLDOM",$J)
140 S CBK("STARTELEMENT")="STARTELE^C0CMXML" ; ONLY THIS ONE IS CHANGED ;GPL
141 S CBK("ENDELEMENT")="ENDELE^MXMLDOM"
142 S CBK("COMMENT")="COMMENT^MXMLDOM"
143 S CBK("CHARACTERS")="CHAR^MXMLDOM"
144 S CBK("ENDDOCUMENT")="ENDDOC^MXMLDOM"
145 S CBK("ERROR")="ERROR^MXMLDOM"
146 S (SUCCESS,LEVEL,LEVEL(0),NODE)=0,OPTION=$G(OPTION,"V1")
147 D EN^MXMLPRSE(DOC,.CBK,OPTION)
148 D:'SUCCESS DELETE^MXMLDOM(HANDLE)
149 Q $S(SUCCESS:HANDLE,1:0)
150 ; Start element
151 ; Create new child node and push info on stack
152STARTELE(ELE,ATTR) ; COPIED FROM STARTELE^MXMLDOM AND MODIFIED TO TREAT
153 ; ATTRIBUTES AS SUBELEMENTS TO MAKE CCD XPATH PROCESSING EASIER
154 N PARENT
155 S PARENT=LEVEL(LEVEL),NODE=NODE+1
156 S:PARENT ^TMP("MXMLDOM",$J,HANDLE,PARENT,"C",NODE)=ELE
157 S LEVEL=LEVEL+1,LEVEL(LEVEL)=NODE,LEVEL(LEVEL,0)=ELE
158 S ^TMP("MXMLDOM",$J,HANDLE,NODE)=ELE,^(NODE,"P")=PARENT
159 ;M ^("A")=ATTR
160 N ZI S ZI="" ; INDEX FOR ATTR
161 F S ZI=$O(ATTR(ZI)) Q:ZI="" D ; FOR EACH ATTRIBUTE
162 . N ELE,TXT ; ABOUT TO RECURSE
163 . S ELE=ZI ; TAG
164 . S TXT=ATTR(ZI) ; DATA
165 . D STARTELE(ELE,"") ; CREATE A NEW SUBNODE
166 . D TXT^MXMLDOM("T") ; INSERT DATA TO TAG
167 . D ENDELE^MXMLDOM(ELE) ; POP BACK UP A LEVEL
168 Q
169 ;
170CLEANARY(OUTARY,INARY) ; GOES THROUGH AN ARRAY AND CALLS CLEAN ON EACH NODE
171 ; INARY AND OUTARY PASSED BY NAME
172 N ZI S ZI=""
173 F S ZI=$O(@INARY@(ZI)) Q:ZI="" D ; FOR EACH NODE
174 . S @OUTARY@(ZI)=$$CLEAN(@INARY@(ZI)) ; CLEAN THE NODE
175 Q
176 ;
177CLEAN(STR) ; extrinsic function; returns string
178 ;; Removes all non printable characters from a string.
179 ;; STR by Value
180 N TR,I
181 F I=0:1:31 S TR=$G(TR)_$C(I)
182 S TR=TR_$C(127)
183 QUIT $TR(STR,TR)
184 ;
185STRIPTXT(OUTARY,ZARY) ; STRIPS THE "TEXT" PORTION OUT OF AN XML FILE
186 ; THIS IS USED TO DELETE THE NARATIVE HTML OUT OF THE CCD XML FILES BECAUSE
187 ; THEY DO NOT WORK RIGHT WITH THE PARSER
188 ;N ZWRK,ZBLD,ZI ; WORK ARRAY,BUILD ARRAY, AND COUNTER
189 S ZI=$O(@ZARY@("")) ; GET FIRST LINE NUMBER
190 D C0CBEGIN("ZWRK",ZI) ; INSERT FIRST LINE IN WORK ARRAY
191 F S ZI=$O(@ZARY@(ZI)) Q:ZI="" D ; FOR EACH LINE OF THE ARRAY
192 . I $O(@ZARY@(ZI))="" D Q ; AT THE END
193 . . D C0CEND("ZWRK",ZI) ; INCLUDE LAST LINE IN WORK ARRAY
194 . I ZI=1 D C0CBEGIN("ZWRK",ZI) ; START WITH FIRST LINE
195 . I @ZARY@(ZI)["<text" D C0CEND("ZWRK",ZI-1) ;PREV LINE IS AN END
196 . I @ZARY@(ZI)["</text>" D C0CBEGIN("ZWRK",ZI+1) ;NEXT LINE IS A BEGIN
197 S ZI=""
198 F S ZI=$O(ZWRK(ZI)) Q:ZI="" D ; MAKE A BUILD LIST FROM THE WORK ARRAY
199 . D QUEUE^C0CXPATH("ZBLD",ZARY,$P(ZWRK(ZI),"^",1),$P(ZWRK(ZI),"^",2))
200 D BUILD^C0CXPATH("ZBLD",OUTARY) ; BUILD NEW ARRAY WITHOUT TEXT SECTIONS
201 K @OUTARY@(0) ; GET RID OF THE LINE COUNT
202 Q
203 ;
204C0CBEGIN(ZA,LN) ; INSERTS A BEGIN LINE LN INTO ARRAY ZWRK, PASSED BY NAME
205 N ZI
206 S ZI=$O(@ZA@(""),-1)
207 I ZI="" S ZI=1
208 E S ZI=ZI+1 ; INCREMENT COUNT IN WORK ARRAY
209 S $P(@ZA@(ZI),"^",1)=LN
210 Q
211 ;
212C0CEND(ZB,LN) ; INSERTS AN END LINE LN INTO ARRAY ZWRK, PASSED BY NAME
213 N ZI
214 S ZI=$O(@ZB@(""),-1)
215 I ZI="" S ZI=1
216 S $P(@ZB@(ZI),"^",2)=LN
217 Q
218 ;
219SEPARATE(OUTARY,INARY) ; SEPARATES XPATH VARIABLES ACCORDING TO THEIR
220 ; ROOT ; /Problems/etc/etc goes to @OUTARY@("Problems","/Problems/etc/etc")
221 S ZI=""
222 F S ZI=$O(@INARY@(ZI)) Q:ZI="" D ; FOR EACH ELEMENT OF THE ARRAY
223 . S ZJ=$P(ZI,"/",2) ;
224 . S @OUTARY@(ZJ,ZI)=@INARY@(ZI)
225 Q
226 ;
227FINDTID ; FIND TEMPLATE IDS IN DOM 1
228 S C0CDOCID=1
229 S ZD=$NA(^TMP("MXMLDOM",$J,C0CDOCID))
230 S ZN=""
231 S CURSEC=""
232 S TID=""
233 F S ZN=$O(@ZD@(ZN)) Q:ZN="" D ;
234 . I $$TAG(ZN)="root" D ;
235 . . I $$TAG($$PARENT(ZN))="templateId" D ; ONLY LOOKING FOR TEMPLATES
236 . . . S ZG=$$PARENT($$PARENT(ZN))
237 . . . S ZG2=$$PARENT(ZG) ;COMPONENT THAT HOLDS THIS SECTION
238 . . . S CMT=$G(@ZD@(ZG,"X",1))
239 . . . I CMT="" S CMT="?"
240 . . . I $$TAG(ZG)="section" D ;START OF A SECTION
241 . . . . S CURSEC=$$PARENT(ZG)
242 . . . . S SECCMT=$G(@ZD@(CURSEC,"X",1))
243 . . . . I SECCMT="" S SECCMT="?"
244 . . . . S SECTID=$G(@ZD@(ZN,"T",1)) ;SECTION TEMPLATE ID
245 . . . S TID=$G(@ZD@(ZN,"T",1)) ;TEMPLATE ID
246 . . . I CURSEC'="" D ; IF WE ARE IN A SECTION
247 . . . . S CCDDIR(ZG2,CURSEC,$$TAG(ZG2),CMT,SECCMT)=TID
248 . . . . S DOMMAP(ZG2)=CURSEC_U_$$TAG(ZG2)_U_TID_U_SECTID
249 . . . W !,$$TAG(ZG2)," ",$G(@ZD@(ZG,"X",1))
250 . . . W " root ",ZN," ",@ZD@(ZN,"T",1)
251 Q
252 ;
253FINDALT ; PROCESS THE DOMMAP AND FIND THE ALT TAGS FOR COMPONENTS
254 ;
255 S ZI=""
256 F S ZI=$O(DOMMAP(ZI)) Q:ZI="" D ; FOR EACH NODE IN THE MAP
257 . S ZJ=DOMMAP(ZI) ;
258 . S PARNODE=$P(ZJ,U,1) ;PARENT NODE
259 . S TAG=$P(ZJ,U,2) ;THIS TAG
260 . S TID=$P(ZJ,U,3) ;THIS TEMPLATE ID
261 . S PARTID=$P(ZJ,U,4) ;PARENT TEMPLATE ID
262 . S ZIEN=$O(^C0CXDS(178.101,"TID",TID,"")) ;THIS NODE IEN
263 . S PARIEN=$O(^C0CXDS(178.101,"TID",PARTID,"")) ;PARENT NODE IEN
264 . I ZI=PARNODE D ; IF THIS IS A SECTION NODE
265 . . S ALTTAG=$$GET1^DIQ(178.101,PARIEN_",",.03) ;ALT TAG FIELD FOR PARENT
266 . . S NAME=$$GET1^DIQ(178.101,ZIEN_",",.01) ;NAME OF THIS NODE'S TEMPLATE
267 . . W ZI," ",TAG," ",ALTTAG," ",NAME,!
268 . . S C0CTAGS(ZI)=ALTTAG
269 Q
270 ;
271ALTTAG(NODE) ; SET Y EQUAL TO THE ALT TAG FOUND IN C0CTAGS IF NODE IF FOUND
272 ;
273 S Y=$G(C0CTAGS(NODE))
274 Q
275 ;
276SETCBK ; SET THE TAG CALLBACK FOR XPATH PROCESSSING OF THE CCD
277 S C0CCBK("TAG")="D ALTTAG(ZOID)"
278 Q
279 ;
280GENXDS(ZD) ; GENERATE THE XDS PROTOTYPE RECORDS FROM A CCDDIR ARRAY
281 ; ARRAY ELEMENTS LOOK LIKE:
282 ; CCDDIR(1659,1634,"observation"," Result observaion template "," Vital signs section template ")="2.16.840.1.113883.10.20.1.31"
283 ;or CCDDIR(cur node,section node,cur tag,cur name,sec name)=templateId
284 S ZF=178.101 ; FILE NUMBER FOR THE C0C XDS PROTOTYPE FILE
285 S ZI=$Q(@ZD@("")) ;FIRST ARRAY ELEMENT
286 S DONE=0
287 F Q:DONE D ;
288 . W @ZI,!
289 . S ZJ=$QS(ZI,5)
290 . S ZJ=$E(ZJ,2,$L(ZJ)) ;STRIP THE LEADING SPACE
291 . S C0CFDA(ZF,"?+1,",.01)=ZJ
292 . S C0CFDA(ZF,"?+1,",.02)=$QS(ZI,4) ; TAG FOR THIS TEMPLATE
293 . S C0CFDA(ZF,"?+1,",1)=@ZI
294 . D UPDIE
295 . S ZI=$Q(@ZI)
296 . I ZI="" S DONE=1
297 Q
298 ;
299WHRUSD(ZD) ; UPDATE THE C0C XDS FILE WITH WHERE USED DATA FROM
300 ; CCDDIR PASS BY NAME
301 ; ARRAY ELEMENTS LOOK LIKE:
302 ; CCDDIR(1634," Vital signs section template ",1659,"observation"," Result observaion template ")="2.16.840.1.113883.10.20.1.31"
303 ;or CCDDIR(section node,sec name, cur node,cur tag,cur name)=templateId
304 S ZF=178.101 ; FILE NUMBER FOR THE C0C XDS PROTOTYPE FILE
305 S ZSF=178.111 ; WHERE USED SUBFILE OF C0C XDS PROTOTYPE FILE
306 S ZI=$Q(@ZD@("")) ;FIRST ARRAY ELEMENT
307 S DONE=0
308 F Q:DONE D ;
309 . W @ZI
310 . S ZIEN=$O(^C0CXDS(178.101,"TID",@ZI,"")) ; IEN FOR THIS NODE'S TEMPLATE
311 . W " IEN:",ZIEN
312 . S ZJ=$QS(ZI,2)
313 . S ZJ=$E(ZJ,2,$L(ZJ)) ;STRIP THE LEADING SPACE
314 . S ZPIEN=$O(^C0CXDS(178.101,"B",ZJ,"")) ; PARENT IEN
315 . W " PARENT IEN:",ZPIEN
316 . S ZTAG=$QS(ZI,4) ; TAG FOR THIS TEMPLATE
317 . W " TAG:",ZTAG,!
318 . I ZIEN'=ZPIEN D ; ONLY FOR CHILD TEMPLATES
319 . . S C0CFDA(ZSF,"?+1,"_ZIEN_",",.01)=ZPIEN ; NEW SUBFILE ENTRY WITH PAR PTR
320 . . S C0CFDA(ZSF,"?+1,"_ZIEN_",",1)=ZTAG ; TAG FOR NEW ENTRY
321 . . D UPDIE
322 . ;S C0CFDA(ZF,"?+1,",1)=@ZI
323 . ;D UPDIE
324 . S ZI=$Q(@ZI)
325 . I ZI="" S DONE=1
326 Q
327 ;
328UPDIE ; INTERNAL ROUTINE TO CALL UPDATE^DIE AND CHECK FOR ERRORS
329 K ZERR
330 D CLEAN^DILF
331 D UPDATE^DIE("","C0CFDA","","ZERR")
332 I $D(ZERR) D ;
333 . W "ERROR",!
334 . ZWR ZERR
335 . B
336 K C0CFDA
337 Q
338 ;
Note: See TracBrowser for help on using the repository browser.