MDXMLFM1 ; HOIFO/DP/NCA - Data -> XML Utilities ; [01-10-2003 09:14]
 ;;1.0;CLINICAL PROCEDURES;**6**;Apr 01, 2004;Build 102
 ; Integration Agreements:
 ; IA# 10035 [Supported] ^DPT references
 ;
 ; Special note: This routine assumes RESULTS contains the closed
 ;               root specification, ^TMP($J) where the output of
 ;               these calls will go.
 ;               i.e. S RESULTS=$NA(^TMP($J))
 ;
 ;               Calling app needs to call NEWDOC^MDXMLFM *ONCE*
 ;               to clear the global before building an XML document.
 ;
LOADALL(IENLIST,DD,FLDS) ; Load complete dataset
 ;
 ; Loads entire dataset from @IENLIST@(...)
 ;
 N MDIEN S MDIEN=0
 D NEWDOC("RESULTS")
 D XMLDATA("STATUS","OK")
 F  S MDIEN=$O(@IENLIST@(MDIEN)) Q:'MDIEN  S MDFDAT=$G(@IENLIST@(MDIEN)) D
 .D BLDXML(DD,MDIEN,.FLDS,MDFDAT)
 D ENDDOC("RESULTS")
 Q
 ;
LOADONE(IEN,DD,FLDS) ; Load single record as dataset
 ;
 ; Not to be used recursively
 ; Assumes complete data set is one record
 ;
 D NEWDOC("RESULTS")
 D XMLDATA("STATUS","OK")
 D BLDXML(DD,IEN,.FLDS)
 D ENDDOC("RESULTS")
 Q
 ;
LOADFILE(MDNUM,MDROOT,MDFLDS) ; Bulk load file MDNUM into XML
 ;
 ; Loads all records and all fields in the DD# MDNUM
 ; Optionally include a closed root of the index to use MDROOT
 ; Optionally include a list of fields #;#;#;# will default to "*"
 ;
 N MDIEN,MDNODE,MDIDS,MDTEMP,MDHDR,MDNAME
 S MDTEMP=$NA(^TMP("MD_TEMP",$J)) K @MDTEMP
 S MDNAME=$$GET1^DID(MDNUM,,,"NAME")
 I $G(MDROOT)]"" S:'$D(@MDROOT)#2 MDROOT=""
 S:$G(MDROOT)="" MDROOT=$$ROOT^DILFD(MDNUM,,1)
 S:$G(MDFLDS)="" MDFLDS="*"
 ;
 ; Load the records via Fileman GETS^DIQ
 ;
 S MDIEN=0
 F  S MDIEN=$O(@MDROOT@(MDIEN)) Q:'MDIEN  D
 .D GETS^DIQ(MDNUM,MDIEN_",",MDFLDS,"I",MDTEMP)
 ;
 ; Grab the tags and types if any records were processed
 ;
 S MDIEN=$O(@MDTEMP@(MDNUM,"")) D:MDIEN]""
 .F X=0:0 S X=$O(@MDTEMP@(MDNUM,MDIEN,X)) Q:'X  D
 ..S MDTAG=$$GET1^DID(MDNUM,X,,"LABEL")
 ..S MDTYPE=$$GET1^DID(MDNUM,X,,"TYPE")
 ..S MDPTR=$$GET1^DID(MDNUM,X,,"POINTER")
 ..S @MDTEMP@(MDNUM,0,X,"TAG")=$$TAGSAFE(MDTAG)
 ..S @MDTEMP@(MDNUM,0,X,"TYPE")=MDTYPE
 ..S @MDTEMP@(MDNUM,0,X,"PTR")=MDPTR
 ;
 ; Ok, lets add the file
 ;
 D XMLDATA("TABLENAME",MDNAME)
 S MDIENS=$O(@MDTEMP@(MDNUM,0))
 F  Q:MDIENS=""  D
 .D XMLHDR("RECORD")
 .S MDFLD=$O(@MDTEMP@(MDNUM,MDIENS,0))
 .F  Q:MDFLD=""  D
 ..S MDTAG=@MDTEMP@(MDNUM,0,MDFLD,"TAG")
 ..S MDATA=@MDTEMP@(MDNUM,MDIENS,MDFLD,"I")
 ..S MDTYPE=@MDTEMP@(MDNUM,0,MDFLD,"TYPE") D
 ...I MDTYPE["WORD" D XMLWP(MDTAG,MDATA) Q
 ...I MDTYPE["DATE" D XMLDT(MDTAG,MDATA) Q
 ...D XMLDATA(MDTAG,MDATA)
 ..S MDFLD=$O(@MDTEMP@(MDNUM,MDIENS,MDFLD))
 .D XMLFTR("RECORD")
 .S MDIENS=$O(@MDTEMP@(MDNUM,MDIENS))
 Q
 ;
BLDFLD(RESULTS,DD,FLDS) ; Add a field or field^field to the FLDS array
 F  D  Q:FLDS']""
 .S Y=$P(FLDS,"^",1),FLDS=$P(FLDS,"^",2,250)
 .S MDFLD=$P(Y,";",1) K RESULTS(MDFLD)
 .I $P(Y,";",2)]"" S RESULTS(MDFLD,"FORMAT")=$P(Y,";",2)
 .E  S RESULTS(MDFLD,"FORMAT")="I"
 .I $P(Y,";",3)]"" S RESULTS(MDFLD,"TAG")=$P(Y,";",3)
 .E  S RESULTS(MDFLD,"TAG")=$TR($$GET1^DID(DD,MDFLD,"","LABEL")," ","_")
 .I $P(Y,";",4)]"" S RESULTS(MDFLD,"TYPE")=$P(Y,";",4)
 .E  S RESULTS(MDFLD,"TYPE")=$$GET1^DID(DD,+MDFLD,"","TYPE")
 Q
 ;
BLDXML(DD,IEN,FLDS,MDFDAT) ; Builds an XML Record based on DD, IEN, and FLDS
 ; Note: this is a standalone module requiring DD and IEN
 ; so that it can be easily used by the custom query routines
 N MDFLD,MDIENS,MDKTR,X,Y
 D XMLHDR("RECORD")
 S MDIENS=IEN_",",MDFLD="",MDKTR=0
 F  S MDFLD=$O(FLDS(MDFLD)) Q:MDFLD=""  D
 .; .001 is always the IEN *IF* it is included in the view
 .I +MDFLD=.001 D XMLDATA(FLDS(MDFLD,"TAG"),+MDIENS) S MDKTR=MDKTR+1 Q
 .S MDFMT=$G(FLDS(MDFLD,"FORMAT"),"I")
 .; Process as a date
 .I $G(FLDS(MDFLD,"TYPE"))["DATE" D  Q
 ..S X=$$GET1^DIQ(DD,MDIENS,MDFLD,"I")
 ..I X]""&(MDFMT'="I") D  S X=Y
 ...S Y=($E(X,1,3)+1700)_"-"_$E(X,4,5)_"-"_$E(X,6,7) Q:X'["."
 ...S X=X+.0000001  ; Add it in ensure all the time parts
 ...S Y=Y_" "_$E(X,9,10)_":"_$E(X,11,12)_":"_$E(X,13,14)
 ..D XMLDATA(FLDS(MDFLD,"TAG"),X)
 .; Process as WP
 .I $G(FLDS(MDFLD,"TYPE"))["WORD" D  Q
 ..D XMLHDR(FLDS(MDFLD,"TAG"))
 ..S Y=$O(@RESULTS@(""),-1)+1
 ..S X=$$GET1^DIQ(DD,MDIENS,MDFLD,"",$NA(@RESULTS@(Y)))
 ..D XMLFTR(FLDS(MDFLD,"TAG"))
 .; Just return with specified data format
 .S MDKTR=MDKTR+1
 .D XMLDATA(FLDS(MDFLD,"TAG"),$P(MDFDAT,U,MDKTR))
 D XMLFTR("RECORD")
 Q
 ;
XMLCMT(COMMENT) ; Add a comment to a document
 D XMLADD("<!-- "_COMMENT_" -->")
 Q
 ;
XMLHDR(TAG) ; Add a header tag to the global
 S TAG=$$TAGSAFE(TAG)
 D XMLADD("<"_TAG_">")
 Q
 ;
XMLFTR(TAG) ; Add a footer tag to the global
 D XMLHDR("/"_TAG)
 Q
 ;
XMLDATA(TAG,X) ; Add a data element to the global
 S TAG=$$TAGSAFE(TAG)
 I $G(X)="" D XMLADD("<"_TAG_" />")
 E  D XMLADD("<"_TAG_">"_$$XMLSAFE(X)_"</"_TAG_">")
 Q
 ;
XMLPT(X) ; Add a standard pt identifier node
 S X(1,"NAME")=$P(^DPT(X,0),U)
 S X(2,"SSN")=$P(^DPT(X,0),U,9)
 S X(3,"SEX")=$P(^DPT(X,0),U,2)
 S Y=$P(^DPT(X,0),U,3)
 S Y(1)=1700+$E(Y,1,3),Y(2)=+$E(Y,4,5),Y(3)=+$E(Y,6,7)
 S X(4,"DOB_Y")=Y(1)
 S X(5,"DOB_M")=Y(2)
 S X(6,"DOB_D")=Y(3)
 D XMLIDS("PATIENT",.X,1)
 Q
 ;
XMLWP(TAG,X) ; Add text in array @X to the global
 S TAG=$$TAGSAFE(TAG)
 I $G(X)="" D XMLADD("<"_TAG_" />") Q  ; Empty global ref
 D XMLHDR(TAG)
 F Y=0:0 S Y=$O(@X@(Y)) Q:'Y  D XMLADD(@X@(Y))
 D XMLFTR(TAG)
 Q
 ;
XMLDT(TAG,X) ; Add date or date/time to the global
 S TAG=$$TAGSAFE(TAG)
 I $G(X)="" D XMLADD("<"_TAG_" />") Q  ; No data
 ; Build the ID array
 S X(1,"Y")=(1700+$E(X,1,3))
 S X(2,"M")=+$E(X,4,5)
 S X(3,"D")=+$E(X,6,7)
 D:X]"."
 .S X=X+.0000001
 .S X(4,"hh")=+$E(X,9,10)
 .S X(5,"mm")=+$E(X,11,12)
 .S X(6,"ss")=+$E(X,13,14)
 D XMLIDS(TAG,.X,1)
 Q
 ;
XMLIDS(TAG,IDS,CLOSE) ; Add a data element to the global with ids
 S TAG="<"_$$TAGSAFE(TAG)
 F X=0:0 S X=$O(IDS(X)) Q:'X  D
 .S Y="" F  S Y=$O(IDS(X,Y)) Q:Y=""  D
 ..S TAG=TAG_" "_Y_"="""_$$XMLSAFE(IDS(X,Y))_""""
 S:$G(CLOSE) TAG=TAG_" /" ; Close out the tag element
 S TAG=TAG_">"
 D XMLADD(TAG)
 Q
 ;
XMLADD(X) ; Add to the global
 S @RESULTS@($O(@RESULTS@(""),-1)+1)=$G(X)
 Q
 ;
ADDERR(X) ;
 S MDERROR($O(MDERR(""),-1)+1)=X
 Q
 ;
XMLOK(RESULTS) ; Build an XML OK message
 K @RESULTS
 S @RESULTS@(0)="<RESULTS>"
 S @RESULTS@(1)="<STATUS>OK</STATUS>"
 S @RESULTS@(2)="</RESULTS>"
 Q
 ;
XMLERR(ERRMSG) ; Build an XML error Message to return
 K @RESULTS
 S @RESULTS@(0)="<RESULTS>"
 S @RESULTS@(1)="<STATUS>ERROR</STATUS>"
 I $D(ERRMSG)=1 D  ; Simple one liner
 .S @RESULTS@(2)="<MESSAGE>"_$$XMLSAFE(ERRMSG)_"</MESSAGE>"
 I $D(ERRMSG)>2 D  ; Load the array into the XML message
 .S @RESULTS@(2)="<MESSAGE>"_$G(ERRMSG,"NO DESCRIPTION")
 .S X="ERRMSG" F  S X=$Q(@X) Q:X=""!(X'?1"ERRMSG(".E)  D
 ..S @RESULTS@($O(@RESULTS@(""),-1)+1)=$$XMLSAFE(@X)
 .S @RESULTS@($O(@RESULTS@(""),-1)+1)="</MESSAGE>"
 S @RESULTS@($O(@RESULTS@(""),-1)+1)="</RESULTS>"
 Q
 ;
XMLDATE(X) ; Transform Y into XML safe date
 N Y
 S Y=($E(X,1,3)+1700)_"-"_$E(X,4,5)_"-"_$E(X,6,7)
 D:X["."
 .S X=X+.0000001
 .S Y=Y_" "_$E(X,9,10)_":"_$E(X,11,12)_":"_$E(X,13,14)
 Q Y
 ;
XMLSAFE(X) ; Transform X into XML safe data
 S X=$$TRNSLT(X,"&","&")
 S X=$$TRNSLT(X,"<","<")
 S X=$$TRNSLT(X,">",">")
 S X=$$TRNSLT(X,"'","'")
 S X=$$TRNSLT(X,"""",""")
 Q X
 ;
TAGSAFE(X) ; Transform X into XML tag
 S:X?1N.E X="_"_X  ; Remove starting numeric
 Q $TR(X," '`()<>*[]","__________")
 ;
NEWDOC(ROOT,COMMENT) ; Start a new document
 K @RESULTS
 D XMLADD("<?xml version=""1.0"" standalone=""yes""?>")
 I $G(COMMENT)]"" D XMLCMT(COMMENT)
 D XMLHDR($G(ROOT,"RESULTS"))
 Q
 ;
ENDDOC(ROOT) ; End this document
 D XMLFTR($G(ROOT,"RESULTS"))
 Q
 ;
TRNSLT(X,X1,X2) ; Translate every Y to Z in X
 N Y
 Q:X'[X1 X  ; Nothing to translate
 S Y="" F  Q:X=""  D
 .I X[X1 S Y=Y_$P(X,X1)_X2,X=$P(X,X1,2,250) Q
 .S Y=Y_X,X=""
 Q Y
 ;
 
--- Routine Detail   --- with STRUCTURED ROUTINE LISTING ---[H[J[2J[HMDXMLFM1   8003     printed  Sep 23, 2025@19:20:36                                                                                                                                                                                                    Page 2
MDXMLFM1  ; HOIFO/DP/NCA - Data -> XML Utilities ; [01-10-2003 09:14]
 +1       ;;1.0;CLINICAL PROCEDURES;**6**;Apr 01, 2004;Build 102
 +2       ; Integration Agreements:
 +3       ; IA# 10035 [Supported] ^DPT references
 +4       ;
 +5       ; Special note: This routine assumes RESULTS contains the closed
 +6       ;               root specification, ^TMP($J) where the output of
 +7       ;               these calls will go.
 +8       ;               i.e. S RESULTS=$NA(^TMP($J))
 +9       ;
 +10      ;               Calling app needs to call NEWDOC^MDXMLFM *ONCE*
 +11      ;               to clear the global before building an XML document.
 +12      ;
LOADALL(IENLIST,DD,FLDS) ; Load complete dataset
 +1       ;
 +2       ; Loads entire dataset from @IENLIST@(...)
 +3       ;
 +4        NEW MDIEN
           SET MDIEN=0
 +5        DO NEWDOC("RESULTS")
 +6        DO XMLDATA("STATUS","OK")
 +7        FOR 
               SET MDIEN=$ORDER(@IENLIST@(MDIEN))
               if 'MDIEN
                   QUIT 
               SET MDFDAT=$GET(@IENLIST@(MDIEN))
               Begin DoDot:1
 +8                DO BLDXML(DD,MDIEN,.FLDS,MDFDAT)
               End DoDot:1
 +9        DO ENDDOC("RESULTS")
 +10       QUIT 
 +11      ;
LOADONE(IEN,DD,FLDS) ; Load single record as dataset
 +1       ;
 +2       ; Not to be used recursively
 +3       ; Assumes complete data set is one record
 +4       ;
 +5        DO NEWDOC("RESULTS")
 +6        DO XMLDATA("STATUS","OK")
 +7        DO BLDXML(DD,IEN,.FLDS)
 +8        DO ENDDOC("RESULTS")
 +9        QUIT 
 +10      ;
LOADFILE(MDNUM,MDROOT,MDFLDS) ; Bulk load file MDNUM into XML
 +1       ;
 +2       ; Loads all records and all fields in the DD# MDNUM
 +3       ; Optionally include a closed root of the index to use MDROOT
 +4       ; Optionally include a list of fields #;#;#;# will default to "*"
 +5       ;
 +6        NEW MDIEN,MDNODE,MDIDS,MDTEMP,MDHDR,MDNAME
 +7        SET MDTEMP=$NAME(^TMP("MD_TEMP",$JOB))
           KILL @MDTEMP
 +8        SET MDNAME=$$GET1^DID(MDNUM,,,"NAME")
 +9        IF $GET(MDROOT)]""
               if '$DATA(@MDROOT)#2
                   SET MDROOT=""
 +10       if $GET(MDROOT)=""
               SET MDROOT=$$ROOT^DILFD(MDNUM,,1)
 +11       if $GET(MDFLDS)=""
               SET MDFLDS="*"
 +12      ;
 +13      ; Load the records via Fileman GETS^DIQ
 +14      ;
 +15       SET MDIEN=0
 +16       FOR 
               SET MDIEN=$ORDER(@MDROOT@(MDIEN))
               if 'MDIEN
                   QUIT 
               Begin DoDot:1
 +17               DO GETS^DIQ(MDNUM,MDIEN_",",MDFLDS,"I",MDTEMP)
               End DoDot:1
 +18      ;
 +19      ; Grab the tags and types if any records were processed
 +20      ;
 +21       SET MDIEN=$ORDER(@MDTEMP@(MDNUM,""))
           if MDIEN]""
               Begin DoDot:1
 +22               FOR X=0:0
                       SET X=$ORDER(@MDTEMP@(MDNUM,MDIEN,X))
                       if 'X
                           QUIT 
                       Begin DoDot:2
 +23                       SET MDTAG=$$GET1^DID(MDNUM,X,,"LABEL")
 +24                       SET MDTYPE=$$GET1^DID(MDNUM,X,,"TYPE")
 +25                       SET MDPTR=$$GET1^DID(MDNUM,X,,"POINTER")
 +26                       SET @MDTEMP@(MDNUM,0,X,"TAG")=$$TAGSAFE(MDTAG)
 +27                       SET @MDTEMP@(MDNUM,0,X,"TYPE")=MDTYPE
 +28                       SET @MDTEMP@(MDNUM,0,X,"PTR")=MDPTR
                       End DoDot:2
               End DoDot:1
 +29      ;
 +30      ; Ok, lets add the file
 +31      ;
 +32       DO XMLDATA("TABLENAME",MDNAME)
 +33       SET MDIENS=$ORDER(@MDTEMP@(MDNUM,0))
 +34       FOR 
               if MDIENS=""
                   QUIT 
               Begin DoDot:1
 +35               DO XMLHDR("RECORD")
 +36               SET MDFLD=$ORDER(@MDTEMP@(MDNUM,MDIENS,0))
 +37               FOR 
                       if MDFLD=""
                           QUIT 
                       Begin DoDot:2
 +38                       SET MDTAG=@MDTEMP@(MDNUM,0,MDFLD,"TAG")
 +39                       SET MDATA=@MDTEMP@(MDNUM,MDIENS,MDFLD,"I")
 +40                       SET MDTYPE=@MDTEMP@(MDNUM,0,MDFLD,"TYPE")
                           Begin DoDot:3
 +41                           IF MDTYPE["WORD"
                                   DO XMLWP(MDTAG,MDATA)
                                   QUIT 
 +42                           IF MDTYPE["DATE"
                                   DO XMLDT(MDTAG,MDATA)
                                   QUIT 
 +43                           DO XMLDATA(MDTAG,MDATA)
                           End DoDot:3
 +44                       SET MDFLD=$ORDER(@MDTEMP@(MDNUM,MDIENS,MDFLD))
                       End DoDot:2
 +45               DO XMLFTR("RECORD")
 +46               SET MDIENS=$ORDER(@MDTEMP@(MDNUM,MDIENS))
               End DoDot:1
 +47       QUIT 
 +48      ;
BLDFLD(RESULTS,DD,FLDS) ; Add a field or field^field to the FLDS array
 +1        FOR 
               Begin DoDot:1
 +2                SET Y=$PIECE(FLDS,"^",1)
                   SET FLDS=$PIECE(FLDS,"^",2,250)
 +3                SET MDFLD=$PIECE(Y,";",1)
                   KILL RESULTS(MDFLD)
 +4                IF $PIECE(Y,";",2)]""
                       SET RESULTS(MDFLD,"FORMAT")=$PIECE(Y,";",2)
 +5               IF '$TEST
                       SET RESULTS(MDFLD,"FORMAT")="I"
 +6                IF $PIECE(Y,";",3)]""
                       SET RESULTS(MDFLD,"TAG")=$PIECE(Y,";",3)
 +7               IF '$TEST
                       SET RESULTS(MDFLD,"TAG")=$TRANSLATE($$GET1^DID(DD,MDFLD,"","LABEL")," ","_")
 +8                IF $PIECE(Y,";",4)]""
                       SET RESULTS(MDFLD,"TYPE")=$PIECE(Y,";",4)
 +9               IF '$TEST
                       SET RESULTS(MDFLD,"TYPE")=$$GET1^DID(DD,+MDFLD,"","TYPE")
               End DoDot:1
               if FLDS']""
                   QUIT 
 +10       QUIT 
 +11      ;
BLDXML(DD,IEN,FLDS,MDFDAT) ; Builds an XML Record based on DD, IEN, and FLDS
 +1       ; Note: this is a standalone module requiring DD and IEN
 +2       ; so that it can be easily used by the custom query routines
 +3        NEW MDFLD,MDIENS,MDKTR,X,Y
 +4        DO XMLHDR("RECORD")
 +5        SET MDIENS=IEN_","
           SET MDFLD=""
           SET MDKTR=0
 +6        FOR 
               SET MDFLD=$ORDER(FLDS(MDFLD))
               if MDFLD=""
                   QUIT 
               Begin DoDot:1
 +7       ; .001 is always the IEN *IF* it is included in the view
 +8                IF +MDFLD=.001
                       DO XMLDATA(FLDS(MDFLD,"TAG"),+MDIENS)
                       SET MDKTR=MDKTR+1
                       QUIT 
 +9                SET MDFMT=$GET(FLDS(MDFLD,"FORMAT"),"I")
 +10      ; Process as a date
 +11               IF $GET(FLDS(MDFLD,"TYPE"))["DATE"
                       Begin DoDot:2
 +12                       SET X=$$GET1^DIQ(DD,MDIENS,MDFLD,"I")
 +13                       IF X]""&(MDFMT'="I")
                               Begin DoDot:3
 +14                               SET Y=($EXTRACT(X,1,3)+1700)_"-"_$EXTRACT(X,4,5)_"-"_$EXTRACT(X,6,7)
                                   if X'["."
                                       QUIT 
 +15      ; Add it in ensure all the time parts
                                   SET X=X+.0000001
 +16                               SET Y=Y_" "_$EXTRACT(X,9,10)_":"_$EXTRACT(X,11,12)_":"_$EXTRACT(X,13,14)
                               End DoDot:3
                               SET X=Y
 +17                       DO XMLDATA(FLDS(MDFLD,"TAG"),X)
                       End DoDot:2
                       QUIT 
 +18      ; Process as WP
 +19               IF $GET(FLDS(MDFLD,"TYPE"))["WORD"
                       Begin DoDot:2
 +20                       DO XMLHDR(FLDS(MDFLD,"TAG"))
 +21                       SET Y=$ORDER(@RESULTS@(""),-1)+1
 +22                       SET X=$$GET1^DIQ(DD,MDIENS,MDFLD,"",$NAME(@RESULTS@(Y)))
 +23                       DO XMLFTR(FLDS(MDFLD,"TAG"))
                       End DoDot:2
                       QUIT 
 +24      ; Just return with specified data format
 +25               SET MDKTR=MDKTR+1
 +26               DO XMLDATA(FLDS(MDFLD,"TAG"),$PIECE(MDFDAT,U,MDKTR))
               End DoDot:1
 +27       DO XMLFTR("RECORD")
 +28       QUIT 
 +29      ;
XMLCMT(COMMENT) ; Add a comment to a document
 +1        DO XMLADD("<!-- "_COMMENT_" -->")
 +2        QUIT 
 +3       ;
XMLHDR(TAG) ; Add a header tag to the global
 +1        SET TAG=$$TAGSAFE(TAG)
 +2        DO XMLADD("<"_TAG_">")
 +3        QUIT 
 +4       ;
XMLFTR(TAG) ; Add a footer tag to the global
 +1        DO XMLHDR("/"_TAG)
 +2        QUIT 
 +3       ;
XMLDATA(TAG,X) ; Add a data element to the global
 +1        SET TAG=$$TAGSAFE(TAG)
 +2        IF $GET(X)=""
               DO XMLADD("<"_TAG_" />")
 +3       IF '$TEST
               DO XMLADD("<"_TAG_">"_$$XMLSAFE(X)_"</"_TAG_">")
 +4        QUIT 
 +5       ;
XMLPT(X)  ; Add a standard pt identifier node
 +1        SET X(1,"NAME")=$PIECE(^DPT(X,0),U)
 +2        SET X(2,"SSN")=$PIECE(^DPT(X,0),U,9)
 +3        SET X(3,"SEX")=$PIECE(^DPT(X,0),U,2)
 +4        SET Y=$PIECE(^DPT(X,0),U,3)
 +5        SET Y(1)=1700+$EXTRACT(Y,1,3)
           SET Y(2)=+$EXTRACT(Y,4,5)
           SET Y(3)=+$EXTRACT(Y,6,7)
 +6        SET X(4,"DOB_Y")=Y(1)
 +7        SET X(5,"DOB_M")=Y(2)
 +8        SET X(6,"DOB_D")=Y(3)
 +9        DO XMLIDS("PATIENT",.X,1)
 +10       QUIT 
 +11      ;
XMLWP(TAG,X) ; Add text in array @X to the global
 +1        SET TAG=$$TAGSAFE(TAG)
 +2       ; Empty global ref
           IF $GET(X)=""
               DO XMLADD("<"_TAG_" />")
               QUIT 
 +3        DO XMLHDR(TAG)
 +4        FOR Y=0:0
               SET Y=$ORDER(@X@(Y))
               if 'Y
                   QUIT 
               DO XMLADD(@X@(Y))
 +5        DO XMLFTR(TAG)
 +6        QUIT 
 +7       ;
XMLDT(TAG,X) ; Add date or date/time to the global
 +1        SET TAG=$$TAGSAFE(TAG)
 +2       ; No data
           IF $GET(X)=""
               DO XMLADD("<"_TAG_" />")
               QUIT 
 +3       ; Build the ID array
 +4        SET X(1,"Y")=(1700+$EXTRACT(X,1,3))
 +5        SET X(2,"M")=+$EXTRACT(X,4,5)
 +6        SET X(3,"D")=+$EXTRACT(X,6,7)
 +7        if X]"."
               Begin DoDot:1
 +8                SET X=X+.0000001
 +9                SET X(4,"hh")=+$EXTRACT(X,9,10)
 +10               SET X(5,"mm")=+$EXTRACT(X,11,12)
 +11               SET X(6,"ss")=+$EXTRACT(X,13,14)
               End DoDot:1
 +12       DO XMLIDS(TAG,.X,1)
 +13       QUIT 
 +14      ;
XMLIDS(TAG,IDS,CLOSE) ; Add a data element to the global with ids
 +1        SET TAG="<"_$$TAGSAFE(TAG)
 +2        FOR X=0:0
               SET X=$ORDER(IDS(X))
               if 'X
                   QUIT 
               Begin DoDot:1
 +3                SET Y=""
                   FOR 
                       SET Y=$ORDER(IDS(X,Y))
                       if Y=""
                           QUIT 
                       Begin DoDot:2
 +4                        SET TAG=TAG_" "_Y_"="""_$$XMLSAFE(IDS(X,Y))_""""
                       End DoDot:2
               End DoDot:1
 +5       ; Close out the tag element
           if $GET(CLOSE)
               SET TAG=TAG_" /"
 +6        SET TAG=TAG_">"
 +7        DO XMLADD(TAG)
 +8        QUIT 
 +9       ;
XMLADD(X) ; Add to the global
 +1        SET @RESULTS@($ORDER(@RESULTS@(""),-1)+1)=$GET(X)
 +2        QUIT 
 +3       ;
ADDERR(X) ;
 +1        SET MDERROR($ORDER(MDERR(""),-1)+1)=X
 +2        QUIT 
 +3       ;
XMLOK(RESULTS) ; Build an XML OK message
 +1        KILL @RESULTS
 +2        SET @RESULTS@(0)="<RESULTS>"
 +3        SET @RESULTS@(1)="<STATUS>OK</STATUS>"
 +4        SET @RESULTS@(2)="</RESULTS>"
 +5        QUIT 
 +6       ;
XMLERR(ERRMSG) ; Build an XML error Message to return
 +1        KILL @RESULTS
 +2        SET @RESULTS@(0)="<RESULTS>"
 +3        SET @RESULTS@(1)="<STATUS>ERROR</STATUS>"
 +4       ; Simple one liner
           IF $DATA(ERRMSG)=1
               Begin DoDot:1
 +5                SET @RESULTS@(2)="<MESSAGE>"_$$XMLSAFE(ERRMSG)_"</MESSAGE>"
               End DoDot:1
 +6       ; Load the array into the XML message
           IF $DATA(ERRMSG)>2
               Begin DoDot:1
 +7                SET @RESULTS@(2)="<MESSAGE>"_$GET(ERRMSG,"NO DESCRIPTION")
 +8                SET X="ERRMSG"
                   FOR 
                       SET X=$QUERY(@X)
                       if X=""!(X'?1"ERRMSG(".E)
                           QUIT 
                       Begin DoDot:2
 +9                        SET @RESULTS@($ORDER(@RESULTS@(""),-1)+1)=$$XMLSAFE(@X)
                       End DoDot:2
 +10               SET @RESULTS@($ORDER(@RESULTS@(""),-1)+1)="</MESSAGE>"
               End DoDot:1
 +11       SET @RESULTS@($ORDER(@RESULTS@(""),-1)+1)="</RESULTS>"
 +12       QUIT 
 +13      ;
XMLDATE(X) ; Transform Y into XML safe date
 +1        NEW Y
 +2        SET Y=($EXTRACT(X,1,3)+1700)_"-"_$EXTRACT(X,4,5)_"-"_$EXTRACT(X,6,7)
 +3        if X["."
               Begin DoDot:1
 +4                SET X=X+.0000001
 +5                SET Y=Y_" "_$EXTRACT(X,9,10)_":"_$EXTRACT(X,11,12)_":"_$EXTRACT(X,13,14)
               End DoDot:1
 +6        QUIT Y
 +7       ;
XMLSAFE(X) ; Transform X into XML safe data
 +1        SET X=$$TRNSLT(X,"&","&")
 +2        SET X=$$TRNSLT(X,"<","<")
 +3        SET X=$$TRNSLT(X,">",">")
 +4        SET X=$$TRNSLT(X,"'","'")
 +5        SET X=$$TRNSLT(X,"""",""")
 +6        QUIT X
 +7       ;
TAGSAFE(X) ; Transform X into XML tag
 +1       ; Remove starting numeric
           if X?1N.E
               SET X="_"_X
 +2        QUIT $TRANSLATE(X," '`()<>*[]","__________")
 +3       ;
NEWDOC(ROOT,COMMENT) ; Start a new document
 +1        KILL @RESULTS
 +2        DO XMLADD("<?xml version=""1.0"" standalone=""yes""?>")
 +3        IF $GET(COMMENT)]""
               DO XMLCMT(COMMENT)
 +4        DO XMLHDR($GET(ROOT,"RESULTS"))
 +5        QUIT 
 +6       ;
ENDDOC(ROOT) ; End this document
 +1        DO XMLFTR($GET(ROOT,"RESULTS"))
 +2        QUIT 
 +3       ;
TRNSLT(X,X1,X2) ; Translate every Y to Z in X
 +1        NEW Y
 +2       ; Nothing to translate
           if X'[X1
               QUIT X
 +3        SET Y=""
           FOR 
               if X=""
                   QUIT 
               Begin DoDot:1
 +4                IF X[X1
                       SET Y=Y_$PIECE(X,X1)_X2
                       SET X=$PIECE(X,X1,2,250)
                       QUIT 
 +5                SET Y=Y_X
                   SET X=""
               End DoDot:1
 +6        QUIT Y
 +7       ;