TMGXMLE2 ;TMG/kst/XML Exporter -- Core functionality ;03/25/06 ;;1.0;TMG-LIB;**1**;07/12/05 ;"TMG XML EXPORT FUNCTIONS (CORE FUNCTIONALITY) ;"Kevin Toppenberg MD ;"GNU General Public License (GPL) applies ;"7-12-2005 ;"======================================================================= ;" API -- Public Functions. ;"======================================================================= ;"WriteXMLData(pArray,Flags,IndentS) ;"Write1File(File,Recs,Flags,IndentS,SavFieldInfo) ;"Write1Rec(File,IEN,Fields,Flags,SRef,IENS,IndentS,RWriter,FWriter,LWriter,WPLWriter,SavFieldInfo) ;"Write1Fld(FileNum,IEN,Field,Fields,Flags,SRef,IENS,IndentS,RWriter,FWriter,LWriter,WPLWriter,SavFieldInfo) ;"======================================================================= ;"PRIVATE API FUNCTIONS ;"======================================================================= ;"======================================================================= ;"DEPENDENCIES ;" TMGDBAPI,TMGDEBUG,TMGMISC,TMGUSRIF ;"======================================================================= ;"======================================================================= ;"The basic format is to be as follows: ;"Array(File,Record,Field,subRec,SubField...)="" <--- means export this entry to XML ;"Array(File,"TEMPLATE",Field) ;"Array(File,"TEMPLATE","ORDER",OrderNum)=Field ;"Array(File,"TEMPLATE","TAG NAME",FieldNumber)="Custom field name to put in XML file" ;"Array("FLAGS","b")="" b -- show tags for ALL fields, even if field has no data ;"Array("FLAGS","i")="" i -- indent tags for pretty, but technically useless, file formating. ;"Array("FLAGS","I")="" I -- output INTERNAL values ;"Array("FLAGS","D")="" D -- output the data dictionary ;"Array("!DOCTYPE")=MyLabel ;"Array("EXPORT_SYSTEM_NAME")=LabelForExportingSystem -- OPTIONAL ;" ;"----------------------------------------------------------------------------------------------- ;"Note: File numbers can be replaces with full FILE NAMES, e.g. ;" Array("NEW PERSON",1234,.01)="" ;" ;"Example: For ALL records, output ALL fields, and ALL subfields ;" Array(8925,"*")="" <--- this is default if Recs is not specified/passed ;" ;"Example: to print from: ;" file 8925, records 1234,1235,1236,1237 ;" file 200, ALL records ;" file 22705, records 3,5 ;" file 2, ALL records ;" ;" Array(8925,1234)="" ;" Array(8925,1235)="" ;" Array(8925,1236)="" ;" Array(8925,1237)="" ;" Array(200,"*")="" ;" Array(22705,3)="" ;" Array(22705,5)="" ;" Array(2,"*")="" ;" ;"Example: Output extra info in record node ;" Array(8925,1232)="tag=value^tag2=value2" <-- optional extra info for record ;" e.g. --> ;" ;"Example: For record 1231, output fields .01 and .02 ;" For record 1232, output field .01 only ;" For record 1234, output field "NAME" only ;" For record 1235, output ALL fields ;" Array(8925,1231,.01)="" ;" Array(8925,1231,.02)="" ;" Array(8925,1232,.01)="" ;" Array(8925,1234,"NAME")="" ;" Array(8925,1235,"*")="" ;" ;"Example: ;" Array(8925,"TEMPLATE",.01)="" <-- define a template for file 8925, with fields .01,.02,.03 ;" Array(8925,"TEMPLATE",.02)="" ;" Array(8925,"TEMPLATE",.03)="" ;" Array(8925,1234) <-- print record 1234 (will use the template) ;" Array(8925,1235) <-- print record 1235 ;" ;"Example: ;" Array(8925,"TEMPLATE","*"))="" <-- include all fields in template ;" Array(8925,"TEMPLATE","Field Exclude",.04)="" <-- but exclude field .04 ;" Array(8925,1235) <-- print record 1235, all fields but .04 ;" ;"Example: For all records, output fields .01 and .02 and "NAME" ;" Array(8925,"*",.01)="" ;" Array(8925,"*",.02)="" ;" Array(8925,"*","NAME")="" ;" ;"Example: ;" Array(8925,1231,"*")="" <--- indicates that ALL fields, ALL subrecs,and ALL subfields are wanted ;" ;"Example: For all records, output field "ENTRY", which is a multiple. In ;" subfile, output all records, fields .01, and .02 ;" Array(8925,"*","ENTRY","*",.01)="" ;" Array(8925,"*","ENTRY","*",.02)="" ;" ;"Example: For ALL records, output ALL fields, and ALL subfields, with 2 exceptions ;" Array(8925,"Rec Exclude",1234)="" <-- All records except 1234 & 1235 will be output ;" Array(8925,"Rec Exclude",1235)="" ;" Array(8925,"*")="" ;" ;"Example: ;" Array(8925,"TEMPLATE","Field Exclude",.04)="" <-- don't show field .04 ;" Array(8925,"TEMPLATE","Field Exclude","STATE")="" <-- don't show field "STATE" ;" Array(8925,1231,"*")="" <-- in record 1231, show all fields but .04 and "STATE" ;" ;"Example: Field .04 is multiple. ALL sub records and ALL subfields to be written ;" Array(8925,1231,.04,"*","*")="" ;" Array(8925,1231,.04,"*")="" <--- "*" assumed for subfields ;" Array(8925,1231,.04)="" <-- "*" assumed for subrecords and subfields. ;" ;"Example: Field .03 is multiple. All sub records to be written (except for #5) , and .01 and .02 fields to be written ;" Array(8925,1231,.03,"*",.01)="" <-- In all sub recs, sub field .01 is to be written ;" Array(8925,1231,.03,"*",.02)="" <-- In all sub recs, sub field .02 is to be written ;" Array(8925,1231,.03,"Rec Exclude",5)="" <-- Exclude subrec 5 ;" ;"Example: Field .03 is multiple. All sub records to be written, and .01 and .02 fields to be written ;" Array(8925,1231,"TEMPLATE",.03,"*","TEMPLATE",.01)="" <-- In all sub recs, sub field .01 is to be written ;" Array(8925,1231,"TEMPLATE",.03,"*","TEMPLATE",.02)="" <-- In all sub recs, sub field .02 is to be written ;"Example: Field .03 is multiple. Sub records 1,2,3 to be written, fields as below ;" Array(8925,1231,.03,1,.01)="" <-- In sub rec 1, sub field .01 is to be written ;" Array(8925,1231,.03,1,.02)="" <-- In sub rec 1, sub field .02 is to be written ;" Array(8925,1231,.03,2,.01)="" <-- In sub rec 2, sub field .01 is to be written ;" Array(8925,1231,.03,3,"*")="" <-- In sub rec 3, all sub fields are to be written ;" Array(8925,1231,.03,4)="" <-- In sub rec 4, all sub fields are to be written (defalt) ;" Array(8925,1231,.03,5,"*")="" <-- In sub rec 5, all sub fields are to be written, with one exception ;" Array(8925,1231,.03,5,"Field Exclude",.01)="" <-- In sub rec 5, sub fields .01 is not to be written. ;" ;"Example: Shows optional substitution of a new tag name for a given field ;" Array(8925,"TEMPLATE","TAG NAME",.01)="Patent Name" <-- use "Patient Name" instead of field name for .01 field ;" Array(8925,"TEMPLATE","TAG NAME",.02)="City" <-- use "City" instead of field name for .02 field ;" ;"Note: pattern continues for sub-sub-multiples etc. ;" ;"Example: ;" Array(8925,1231,.01)="" ;" Array(8925,1231,.02)="" ;" Array(8925,1231,"NAME")="" <--- note that field name is allowed in place of number ;" Array(8925,1231,.03,1,.01)="" <-- In sub rec 1, sub field .01 is to be written ;" Array(8925,1231,.03,1,.02)="" <-- In sub rec 1, sub field .02 is to be written ;" Array(8925,1231,.03,2,.01)="" <-- In sub rec 2, sub field .01 is to be written ;" Array(8925,1231,.03,3,"*")="" <-- In sub rec 3, all sub fields are to be written ;" Array(8925,1231,.03,4)="" <-- In sub rec 4, all sub fields are to be written (defalt) ;" ;"Example: Field .03 is a multiple ;" Array(8925,1231,.03,"TEMPLATE",.01)="" ;" Array(8925,1231,.03,"TEMPLATE",.02)="" ;" Array(8925,1231,.03,1)="" <-- In sub rec 1, export fields .01,.02 from template ;" Array(8925,1231,.03,2)="" <-- In sub rec 2, export fields .01,.02 from template ;" Array(8925,1231,.03,4)="" <-- In sub rec 4, export fields .01,.02 from template ;" ;"Example: ;" Array(8925,"TEMPLATE","ORDER",1)=.03 <-- 1st field to output ;" Array(8925,"TEMPLATE","ORDER",2)=.02 <-- 2nd field to output ;" Array(8925,"TEMPLATE","ORDER",3)="NAME" <-- 3rd field to output ;" Array(8925,"TEMPLATE","ORDER",4)=.01 <-- 4th field to output ;" Note: Specifying an 'ORDER' is not compatible with specifying "*" fields ;" If "ORDER" is specified, only fields with a given order will be output ;" Both Field("ORDER",x)=FieldNum *AND* Field(FieldNum)="" should be defined ;" This will be primarily important for fields that are multiples, with sub recs. ;" ;"Example: ;" Array(8925,"TEMPLATE","TRANSFORM",.01)="write ""Custom .01 output transform M code here...""" ;" Array(8925,"TEMPLATE","TRANSFORM",.02)="write ""Custom .02 output transform M code here...""" WriteXMLData(pArray,Flags,IndentS,ShowProgress) ;"Scope: PUBLIC ;"Purpose: to dump out a specified set of files and records in XML Format ;"Input: pArray -- pointer to (i.e. name of) array containting formatting/output info. ;" REQUIRED An array specifying which files and records to display ;" Format as follows: ;" ;"----------------------------------------- ;" Array(File,IEN,FieldInfo) ; For FieldInfo, see Write1File, and Write1Rec ;" Array(File,["TEMPLATE"],...) ;For Template info see function Write1File ;" Array("FLAGS","b")="" b -- show tags for ALL fields, even if field has no data ;" Array("FLAGS","i")="" i -- indent tags for pretty, but technically useless, file formating. ;" Array("FLAGS","I")="" I -- output INTERNAL values ;" Array("FLAGS","D")="" D -- output the data dictionary ;" Array("FLAGS","S")="" S -- output export settings. ;" Array("!DOCTYPE")=MyLabel ;" Array("EXPORT_SYSTEM_NAME")=LabelForExportingSystem -- OPTIONAL ;" ;"----------------------------------------- ;" ;" e.g. Array(8925,1234)="" ;" Array(8925,1235)="" ;" Array(8925,1236)="" ;" Array(8925,1237)="" ;" Array(8925,1232)="tag=value^tag2=value2" <-- optional extra info for record ;" e.g. --> ;" Array(200,"*")="" ;" Array(22705,3)="" ;" Array(22705,5)="" ;" Array(2,"*")="" ;" ;" This would print from: ;" file 8925, records 1234,1235,1236,1237 ;" file 200, ALL records ;" file 22705, records 3,5 ;" file 2, ALL records ;" ;" Example: ;" Array(8925,"TEMPLATE",.01)="" <-- define a template for file 8925 ;" Array(8925,"TEMPLATE",.02)="" ;" Array(8925,"TEMPLATE",.02)="" ;" Array(8925,1234) <-- print record 1234 ;" Array(8925,1235) <-- print record 1235 ;" ;" Example: ;" Array(8925,1234) <-- print record 1234 ;" Array(8925,1235) <-- print record 1235 ;" ;" Example: ;" Array(8925,1234,.01) <-- print record 1234, only field .01 ;" Array(8925,1235,.04) <-- print record 1235, only field .04 ;" ;" Note: File numbers can be replaces with full FILE NAMES, e.g. ;" Array("NEW PERSON","*")="" ;" ;" Note: All File numbers and field numbers can be replaced with NAMES ;" ;" Flags -- OPTIONAL (Note Flags can also be specified with a "FLAGS" node) ;" b -- show tags for ALL fields, even if field has no data ;" i -- indent tags for pretty, but technically useless, file formating. ;" I -- output INTERNAL values ;" D -- output Data dictionary ;" e.g. Flags="b" or "bi" or "ib" or "iI" etc. ;" IndentS -- OPTIONAL -- current string to write to indent line. ;" IndentS("IncIndent")=IncIndent ;" ShowProgress -- OPTIONAL -- if =1, then a progress bar will be shown. ;"Output: results are written to the current device. ;"result : none new File,tArray,SavFieldInfo merge tArray=@pArray set Flags=$get(Flags) new IncIndent set IncIndent=$get(IndentS("IncIndent")," ") if ($data(tArray("FLAGS","b"))>0)&(Flags'["b") set Flags=Flags_"b" if ($data(tArray("FLAGS","i"))>0)&(Flags'["i") set Flags=Flags_"i" if ($data(tArray("FLAGS","I"))>0)&(Flags'["I") set Flags=Flags_"I" if ($data(tArray("FLAGS","D"))>0)&(Flags'["D") set Flags=Flags_"D" if ($data(tArray("FLAGS","S"))>0)&(Flags'["S") set Flags=Flags_"S" do WriteHeader write "",! new SrcName set SrcName=$get(tArray("EXPORT_SYSTEM_NAME"),"?Unnamed?") write "",! set IndentS=$get(IndentS)_IncIndent if Flags["S" do WriteSettings(.Flags,.IndentS) ;"output writing settings set File="" for set File=$order(tArray(File)) quit:(+File'>0) do . new IEN,Template,Recs . merge Template=tArray(File,"TEMPLATE") . kill tArray(File,"TEMPLATE") . merge Recs=tArray(File) . set IEN=$order(tArray(File,"")) . if IEN'="" do . . if $data(TMGXDEBUG) do . . . use $P write "Writing file: ",File,! use IO . . if IEN="*" do . . . do Write1File(File,.Recs,.Flags,.IndentS,.Template,.ShowProgress,,,,,.SavFieldInfo) . . else do . . . new Recs merge Recs=tArray(File) . . . do Write1File(File,.Recs,.Flags,.IndentS,,.ShowProgress,,,,,.SavFieldInfo) write "",! quit WriteHeader ;"Scope: PUBLIC ;"Purpose: A shell to write out a proper XML header. This should be done prior ;" to writing out XML formatted data to a device ;"Output: Header is output to current device ;"Results: none new s set s=$$XMLHDR^MXMLUTL write s,! quit Write1File(File,Recs,Flags,IndentS,Template,ShowProgress,RWriter,FWriter,LWriter,WPLWriter,SavFieldInfo) ;"Scope: PUBLIC ;"Purpose: to dump out (in XML) one file, for specified records ;"Input: File -- name or number of file to dump ;" Recs -- OPTIONAL. PASS BY REFERENCE (default is to write ALL records) ;" To specify records to write out, use Recs array with following format: ;" ------------------------------------------------------------------- ;" Recs(IEN,Field,FieldInfo); (Default for all is "*") ;" For format of FieldInfo, see function Write1Rec ;" Recs("Rec Exclude",IEN) <-- exclude IEN from output ;" ------------------------------------------------------------------- ;" Example: ;" Recs(1231)="" ;" Recs(1232)="" ;" Recs(1234)="" this would be used to print records 1231,1232,1234 ;" Recs(1232)="tag=value^tag2=value2" <-- optional extra info for record ;" e.g. ;" ;" Example: For ALL records, output ALL fields, and ALL subfields ;" Recs("*")="" <--- this is default if Recs is not specified/passed ;" Example: For all records, output fields .01 and .02 and "NAME" ;" Recs("*",.01)="" ;" Recs("*",.02)="" ;" Recs("*","NAME")="" ;" Example: For record 1231, output fields .01 and .02 ;" For record 1232, output field .01 only ;" For record 1234, output field "NAME" only ;" For record 1235, output ALL fields ;" Recs(1231,.01)="" ;" Recs(1231,.02)="" ;" Recs(1232,.01)="" ;" Recs(1234,"NAME")="" ;" Recs(1235,"*")="" ;" Example: For all records, output field "ENTRY", which is a multiple. In ;" subfile, output records .01, and .02 ;" Recs("*","ENTRY",.01)="" ;" Recs("*","ENTRY",.02)="" ;" Example: For ALL records, output ALL fields, and ALL subfields, with 2 exceptions ;" Recs("*")="" ;" Recs("Rec Exclude",1234)="" <-- All records except 1234 & 1235 will be output ;" Recs("Rec Exclude",1235)="" ;" Flags -- OPTIONAL ;" b -- show tags for ALL fields, even if field has no data ;" i -- indent tags for pretty, but technically useless, file formating. ;" I -- output INTERNAL values ;" D -- include data dictionary for file. ;" S -- output export settings ;" IndentS -- OPTIONAL -- current string to write to indent line. ;" IndentS("IncIndent")=IncIndent ;" Template -- OPTIONAL. PASS BY REFERENCE ;" This can be used for instances where the same set of fields are desired for ;" multiple records. ;" Example: ;" Recs(1231)="" ;" Recs(1232)="" ;" Recs(1234)="" ;" with Template(.01)="" ;" Template(.02)="" ;" Is the same as specifying: ;" Recs(1231,.01)="" ;" Recs(1231,.02)="" ;" Recs(1232,.01)="" ;" Recs(1232,.02)="" ;" Recs(1234,.01)="" ;" Recs(1234,.02)="" ;" ShowProgress -- OPTIONAL -- if >0, then a progress bar will be shown. ;" RWriter -- OPTIONAL -- the name of a custom function to use for writing ;" actual starting and ending . e.g. ;" "MyCustomFn". Note do NOT include parameters. Function named ;" as custom function must accept same parameters as WriteRLabel ;" FWriter -- OPTIONAL -- the name of a custom function to use for writing ;" actual line of text out. e.g. "WriteFLabel" or ;" "MyCustomFn". Note do NOT include parameters. Function named ;" LWriter -- OPTIONAL -- the name of a custom function to use for writing ;" actual line of text out for WP fields. e.g. "WriteLine" or ;" "MyCustomFn". Note do NOT include parameters. Function named ;" as custom function must accept same parameters as WriteLine ;" as custom function must accept same parameters as WriteFLabel ;" WPLWriter -- OPTIONAL -- the name of a custom function to use for writing ;" actual line of text out for WP fields. If not provided, then ;" LWriter will be used instead. ;" e.g. "WriteWPLine" or "MyWPCustomFn". Note do NOT include parameters. ;" Function named as custom function must accept same parameters as WriteLine ;" SavFieldInfo -- OPTIONAL -- PASS BY REFERENCE. An array to hold lookup values about ;" fields, so it doesn't have to be done each time (faster) ;"Output: results are written to the current device. ;"result : none new ORoot,GRef new FileNum,FName new prgsCt set prgsCt=0 new prgsMax new IncIndent set IncIndent=$get(IndentS("IncIndent")," ") if $data(Template)=0 set Template("*")="" new RecsSpecified set RecsSpecified=(($data(Recs)>1)&($data(Recs("*"))=0)) new keyin set keyin=32 new startTime set startTime=$H set RWriter=$get(RWriter,"WriteRLabel") set IndentS=$get(IndentS) set FileNum=+$get(File) if FileNum=0 do . set FileNum=$$GetFileNum^TMGDBAPI(.File) . set FName=File else do . set FName=$order(^DD(FileNum,0,"NM","")) if FileNum=0 do goto WFDone . do ShowError^TMGDEBUG(.PriorErrorFound,"Can't convert file '"_$get(File)_", to a number.") set ORoot=$$GET1^DID(FileNum,"","","GLOBAL NAME") ;" Get global root (Thanks, Don Donati...) set GRef=$$CREF^DILF(ORoot) ;" Convert open to closed root if $get(ShowProgress) do . if RecsSpecified do . . set prgsMax=$$ListCt^TMGMISC("Recs") . else do . . set prgsMax=0 . . set IEN=$order(@GRef@("")) ;"count ALL records in file. . . for do quit:(IEN'>0) . . . set IEN=$order(@GRef@(IEN)) . . . if +IEN>0 set prgsMax=prgsMax+1 set Flags=$get(Flags) if Flags["i" write IndentS write "",! if Flags["D" do WriteDD(FileNum,Flags,IndentS_IncIndent) ;"write out data dictionary file new IndS2 set IndS2=IndentS_IncIndent new IEN set IEN=0 for do quit:(IEN'>0) . if $data(Fields)'>1 set Fields("*")="" . if RecsSpecified do . . set IEN=$order(Recs(IEN)) ;"Cycle through specified records . . new Extra set Extra=$get(Recs(IEN)) . . if Extra'="" do ;"parse extra info into IEN array for output . . . new s,n,tag,value . . . for n=1:1:$length(Extra,"^") do . . . . set s=$piece(Extra,"^",n) . . . . if s'["=" quit . . . . set tag=$piece(s,"=",1) . . . . set value=$piece(s,"=",2) . . . . set IEN(tag)=value . else do . . set IEN=$order(@GRef@(IEN)) ;"Cycle through ALL records in file. . if (IEN'>0) quit . if $data(Recs("Rec Exclude",IEN)) quit ;"skip excluded records . new Fields merge Fields=Recs(IEN) . if $data(Fields)'>1 merge Fields=Template . if $get(Flags)["i" write $get(IndS2) . new exFn set exFn="do "_RWriter_"(.IEN,0)" . xecute exFn . if $data(TMGXDEBUG) do . . use $P . . write "Writing record: ",IEN," prgsCt=",prgsCt," prgsMax=",prgsMax,! . . use IO . do Write1Rec(FileNum,IEN,.Fields,.Flags,"","",IndS2_IncIndent,.RWriter,.FWriter,.LWriter,.WPLWriter,.SavFieldInfo) . if $get(Flags)["i" write $get(IndS2) . set exFn="do "_RWriter_"(.IEN,1)" . xecute exFn . set prgsCt=prgsCt+1 . if $get(ShowProgress)&(prgsCt#2=1) do . . use $P . . do ProgressBar^TMGUSRIF(prgsCt,"Writing "_FName,1,prgsMax,,startTime) . . use IO . ;"use $P read *keyin use IO . if keyin=27 do . . new Abort . . use $P . . write prgsCt," records written so far...",! . . write !,"Do you want to abort XML export? NO// " . . read Abort:$get(DTIME,3600),! . . if Abort="" set Abort="NO" . . if "YESyesYes"[Abort set IEN=0 ;"abort signal . . write "OK. Continuing...",! . . use IO if $get(Flags)["i" write IndentS write "",! if $get(ShowProgress) do . use $P . do ProgressBar^TMGUSRIF(100,"Writing "_FName,1,100) . use IO WFDone quit WriteSettings(Flags,IndentS) ;"Scope: PRIVATE ;"Purpose: to output XML output settings. ;"Input: Flags -- flags as declared above. Only "i" used here ;" IndentS -- OPTIONAL -- current string to write to indent line. ;" IndentS("IncIndent")=IncIndent ;"NOTE: Uses GLOBAL SCOPED IncIndent variable. But setting this is OPTIONAL. ;"Results: none set IndentS=$get(IndentS) set Flags=$get(Flags) new IncIndent set IncIndent=$get(IndentS("IncIndent")," ") if Flags["i" write IndentS write "",! new fArray,fl set fArray("i")="Indent_Output" set fArray("b")="Output_Blanks" set fArray("I")="Output_Internal_Values" set fArray("D")="Output_Data_Dictionary" set fl="" for set fl=$order(fArray(fl)) quit:(fl="") do . if Flags["i" write IndentS_IncIndent . write "" . write $select((Flags[fl):"TRUE",1:"FALSE") . write "",! if Flags["i" write IndentS write "",! quit WriteDD(FileNum,Flags,IndentS) ;"Scope: PRIVATE ;"Purpose: to write out data dictionary file, ^DIC,and file Header in XML format ;"Input: FileNum -- the file number (not name) of the data dictionary to export ;" Flags -- flags as declared above. Only "i" used here ;" IndentS -- OPTIONAL -- current string to write to indent line. ;"NOTE: Uses GLOBAL SCOPED IncIndent variable. But setting this is OPTIONAL. ;"Results: none new ProgressFn use $P write ! use IO set IncIndent=$get(IncIndent," ") set ProgressFn="use $P do ProgressBar^TMGUSRIF(IncVar,""^DD("_FileNum_")"",0,100000,,"""_$H_""") use IO" do WriteArray^TMGXMLT($name(^DD(FileNum)),"DataDictionary",FileNum,.Flags,.IndentS,.IncIndent,.ProgressFn) set ProgressFn="use $P do ProgressBar^TMGUSRIF(IncVar,""^(DIC("_FileNum_")"",0,1000000,,"""_$H_""") use IO" new DIC ;"Pull just the fileman nodes. ^DIC also contains some full files... merge DIC(FileNum,0)=^DIC(FileNum,0) merge DIC(FileNum,"%")=^DIC(FileNum,"%") merge DIC(FileNum,"%A")=^DIC(FileNum,"%A") merge DIC(FileNum,"%D")=^DIC(FileNum,"%D") do WriteArray^TMGXMLT("DIC("_FileNum_")","DIC_File",FileNum,.Flags,.IndentS,.IncIndent,.ProgressFn) do . new Ref set Ref=$get(^DIC(FileNum,0,"GL")) . set Ref=$$CREF^DILF(Ref) ;" Convert open to closed root . if $get(Flags)["i" write IndentS . write "",! . if $get(Flags)["i" write IndentS . write $get(@Ref@(0)),! . if $get(Flags)["i" write IndentS . write "",! ;"use $P write ! use IO quit Write1Rec(File,IEN,Fields,Flags,SRef,IENS,IndentS,RWriter,FWriter,LWriter,WPLWriter,SavFieldInfo) ;"Scope: PUBLIC ;"Purpose: To dump one record out in XML format ;"Input: File -- name or number of file to dump ;" IEN -- Record number (IEN) to dump (see also IENS below) ;" Fields -- OPTIONAL. PASS BY REFERENCE. Array of fields to write, format at follows ;" Fields(Field,[SubRecNums,[SubFields,...]])="" ;" Fields(Field,["Rec Exclude",Excluded IEN])="" ;" Fields("Field Exclude",ExcludedField)="" <-- OPTIONAL ;" Fields("ORDER",OrderNum)=Field <-- OPTIONAL ;" Fields("TAG NAME",FieldNumber)="Custom field name to put in XML file" <-- OPTIONAL ;" ;" Example: ;" Fields(.01)="" ;" Fields(.02)="" ;" Fields("NAME")="" <--- note that field name is allowed in place of number ;" Fields(.03)="" ;" ;" Example: ;" Fields("*")="" <--- indicates that ALL fields, ALL subrecs,and ALL subfields are wanted ;" ;" Example: ;" Fields("*")="" ;" Fields("Field Exclude",.04)="" <-- don't show field .04 ;" Fields("Field Exclude","STATE")="" <-- don't show field "STATE" ;" ;" Example: Field .04 is multiple. ALL sub records and ALL subfields to be written ;" Fields(.04,"*","*")="" ;" Fields(.04,"*")="" <--- "*" assumed for subfields ;" Fields(.04)="" <-- "*" assumed for subrecords and subfields. ;" ;" Example: Field .03 is multiple. All sub records to be written, and .01 and .02 fields to be written ;" Fields(.03,"*",.01)="" <-- In all sub recs, sub field .01 is to be written ;" Fields(.03,"*",.02)="" <-- In all sub recs, sub field .02 is to be written ;" Fields(.03,"Rec Exclude",5)="" <-- Exclude subrec 5 ;" ;" Example: Field .03 is multiple. Sub records 1,2,3 to be written, fields as below ;" Fields(.03,1,.01)="" <-- In sub rec 1, sub field .01 is to be written ;" Fields(.03,1,.02)="" <-- In sub rec 1, sub field .02 is to be written ;" Fields(.03,2,.01)="" <-- In sub rec 2, sub field .01 is to be written ;" Fields(.03,3,"*")="" <-- In sub rec 3, all sub fields are to be written ;" Fields(.03,4)="" <-- In sub rec 4, all sub fields are to be written (defalt) ;" Fields(.03,5,"*")="" <-- In sub rec 5, all sub fields are to be written, with one exception ;" Fields(.03,5,"Field Exclude",.01)="" <-- In sub rec 5, sub fields .01 is not to be written. ;" ;" Example: Shows optional substitution of a new tag name for a given field ;" Fields("TAG NAME",.01)="Patent Name" <-- use "Patient Name" instead of field name for .01 field ;" Fields("TAG NAME",.02)="City" <-- use "City" instead of field name for .02 field ;" ;" Example: ;" Array("TRANSFORM",.01)="write ""Custom .01 output transform M code here...""" ;" Array("TRANSFORM",.02)="write ""Custom .02 output transform M code here...""" ;" ;" Note: pattern continues for sub-sub-multiples etc. ;" ;" Example: ;" Fields(.01)="" ;" Fields(.02)="" ;" Fields("NAME")="" <--- note that field name is allowed in place of number ;" Fields(.03,1,.01)="" <-- In sub rec 1, sub field .01 is to be written ;" Fields(.03,1,.02)="" <-- In sub rec 1, sub field .02 is to be written ;" Fields(.03,2,.01)="" <-- In sub rec 2, sub field .01 is to be written ;" Fields(.03,3,"*")="" <-- In sub rec 3, all sub fields are to be written ;" Fields(.03,4)="" <-- In sub rec 4, all sub fields are to be written (defalt) ;" Fields("ORDER",1)=.03 <-- 1st field to output ;" Fields("ORDER",2)=.02 <-- 2nd field to output ;" Fields("ORDER",3)="NAME" <-- 3rd field to output ;" Fields("ORDER",4)=.01 <-- 4th field to output ;" Note: Specifying an 'ORDER' is not compatible with specifying "*" fields ;" If "ORDER" is specified, only fields with a given order will be output ;" Both Field("ORDER",x)=FieldNum *AND* Field(FieldNum)="" should be defined ;" This will be primarily important for fields that are multiples, with sub recs. ;" ;" Flags -- OPTIONAL ;" b -- show tags for fields, even if field has no data ;" i -- indent tags for pretty, but technically useless, file formating. ;" I -- output INTERNAL values ;" SRef -- OPTIONAL (Used only when calling self recursively) ;" IENS -- OPTIONAL a standard IENS string ;" e.g. "IEN,parent-IEN,grandparent-IEN," etc. ;" This is used when calling self recursively, to handle subfiles ;" IndentS -- OPTIONAL -- current string to write to indent line. ;" RWriter -- OPTIONAL -- the name of a custom function to use for writing ;" actual starting and ending . e.g. ;" "MyCustomFn". Note do NOT include parameters. Function named ;" as custom function must accept same parameters as WriteRLabel ;" FWriter -- OPTIONAL -- the name of a custom function to use for writing ;" actual line of text out. e.g. "WriteFLabel" or ;" "MyCustomFn". Note do NOT include parameters. Function named ;" as custom function must accept same parameters as WriteFLabel ;" LWriter -- OPTIONAL -- the name of a custom function to use for writing ;" actual line of text out for fields. e.g. "WriteLine" or ;" "MyCustomFn". Note do NOT include parameters. Function named ;" as custom function must accept same parameters as WriteLine ;" WPLWriter -- OPTIONAL -- the name of a custom function to use for writing ;" actual line of text out for WP fields. If not provided, then ;" LWriter will be used instead. ;" e.g. "WriteWPLine" or "MyWPCustomFn". Note do NOT include parameters. ;" Function named as custom function must accept same parameters as WriteLine ;" SavFieldInfo -- OPTIONAL -- PASS BY REFERENCE. An array to hold lookup values about ;" fields, so it doesn't have to be done each time (faster) ;"Output: Values are written to the current device ;"Results: None ;"Note: this code began its life as a function written by Greg Woodhouse (thanks Greg!) new Field,FldType,FieldInfo new StoreLoc,Node,Pos new IntValue,ORoot,GRef new Range,FIRST,LAST new SubFile,SRoot,CRoot new SubRec,VAL2,Label new FileNum new IncIndent set IncIndent=" " if $data(Fields)<10 set Fields("*")="" new AllFields set AllFields=($data(Fields("*"))>0) new OrdFields,OrdIndex set OrdFields=0,OrdIndex=0 if $order(Fields("ORDER"))>1 set AllFields=0,OrdFields=1 new LastFileName set FileNum=+$get(File) if FileNum=0 set FileNum=$$GetFileNum^TMGDBAPI(.File) if FileNum=0 do goto WRDone . do ShowError^TMGDEBUG(.PriorErrorFound,"Can't convert file '"_$get(File)_", to a number.") if $get(IENS)="" set IENS=IEN_"," set Field=0 set LastFileName=Field ;"Ensure all text exclusion fields are converted to numeric ones. if $data(Fields("Field Exclude"))>0 do . new field . set field=$order(Fields("Field Exclude","")) . if field'="" for do quit:(field="") . . if +field'=field do . . . new tempField . . . set tempField=$$GetNumField^TMGDBAPI(FileNum,field) . . . set Fields("Field Exclude",tempField)="" . . set field=$order(Fields("Field Exclude",field)) ;"Ensure all custom tag field names are converted to numeric ones. if $data(Fields("TAG NAME"))>0 do . new field . set field=$order(Fields("TAG NAME","")) . if field'="" for do quit:(field="") . . if +field'=field do . . . new tempField . . . set tempField=$$GetNumField^TMGDBAPI(FileNum,field) . . . set Fields("TAG NAME",tempField)=Fields("TAG NAME",field) . . set field=$order(Fields("TAG NAME",field)) ;"Ensure all custom TRANSFORM field names are converted to numeric ones. if $data(Fields("TRANSFORM"))>0 do . new field . set field=$order(Fields("TRANSFORM","")) . if field'="" for do quit:(field="") . . if +field'=field do . . . new tempField . . . set tempField=$$GetNumField^TMGDBAPI(FileNum,field) . . . set Fields("TRANSFORM",tempField)=Fields("TRANSFORM",field) . . set field=$order(Fields("TRANSFORM",field)) ;"NOTE: It is ineffecient to call a function for each field. That requires ;" the field function to call $$GET1^DIQ. A more effecient way would ;" be to call GETS^DIQ to get ALL the field's values at once, and then ;" pass the value to the field function. FIX LATER... for do quit:(+Field'>0) . if AllFields do . . set Field=$order(^DD(FileNum,Field)) . else if OrdFields do quit:(Field="") . . set OrdIndex=$order(Fields("ORDER",OrdIndex)) . . set Field=$get(Fields("ORDER",OrdIndex)) . else do quit:(+Field'>0) . . set Field=$order(Fields(LastFileName)) . set LastFileName=Field . if +Field=0 set Field=$$GetNumField^TMGDBAPI(FileNum,Field) . if $data(Fields("Field Exclude",Field))>0 quit . if +Field=0 quit . do Write1Fld(FileNum,IEN,Field,.Fields,.Flags,.SRef,.IENS,.IndentS,.RWriter,.FWriter,.LWriter,.WPLWriter,.SavFieldInfo) WRDone quit Write1Fld(FileNum,IEN,Field,Fields,Flags,SRef,IENS,IndentS,RWriter,FWriter,LWriter,WPLWriter,SavFieldInfo) ;"Scope: PUBLIC ;"Purpose: To dump one field out in XML format ;"Input: FileNum -- number of file containing field ;" IEN -- Record number (IEN) to dump (see also IENS below). Ignored if IENS supplied ;" Field -- The field number to write from array below. ;" Fields -- The field to write. ;" Flags -- OPTIONAL ;" b -- show tags for fields, even if field has no data ;" i -- indent tags for pretty, but technically useless, file formating. ;" I -- output INTERNAL values ;" SRef -- OPTIONAL (Used only when calling self recursively) ;" IENS -- OPTIONAL a standard IENS string ;" e.g. "IEN,parent-IEN,grandparent-IEN," etc. ;" This is used when calling self recursively, to handle subfiles ;" Late Note: if IENS is supplied, then IEN is ignored ;" IndentS -- OPTIONAL -- current string to write to indent line. ;" RWriter -- OPTIONAL -- the name of a custom function to use for writing ;" actual starting and ending . e.g. ;" "MyCustomFn". Note do NOT include parameters. Function named ;" as custom function must accept same parameters as WriteRLabel ;" FWriter -- OPTIONAL -- the name of a custom function to use for writing ;" actual line of text out. e.g. "WriteFLabel" or ;" "MyCustomFn". Note do NOT include parameters. Function named ;" as custom function must accept same parameters as WriteFLabel ;" LWriter -- OPTIONAL -- the name of a custom function to use for writing ;" actual line of text out for WP fields. e.g. "WriteLine" or ;" "MyCustomFn". Note do NOT include parameters. Function named ;" as custom function must accept same parameters as WriteLine ;" WPLWriter -- OPTIONAL -- the name of a custom function to use for writing ;" actual line of text out for WP fields. If not provided, then ;" LWriter will be used instead. ;" e.g. "WriteWPLine" or "MyWPCustomFn". Note do NOT include parameters. ;" Function named as custom function must accept same parameters as WriteLine ;" SavFieldInfo -- OPTIONAL -- PASS BY REFERENCE. An array to hold lookup values about ;" fields, so it doesn't have to be done each time (faster) ;"Output: Values are written to the current device ;"Results: None ;"Note: this code began its life as a function written by Greg Woodhouse (thanks Greg!) new FldType,Label new FieldInfo if $get(IENS)="" set IENS=IEN_"," if +$get(Field)=0 goto W1FDone set FWriter=$get(FWriter,"WriteFLabel") set RWriter=$get(RWriter,"WriteRLabel") set LWriter=$get(LWriter,"WriteLine") set WPLWriter=$get(WPLWriter,LWriter) set Flags=$get(Flags) if 1=1 do . if $data(SavFieldInfo(FileNum,Field))>0 do . . merge FieldInfo=SavFieldInfo(FileNum,Field) . else do . . do GetFieldInfo^TMGDBAPI(FileNum,Field,"FieldInfo","LABEL") . . merge SavFieldInfo(FileNum,Field)=FieldInfo else if 1=0 do . ;"try to get info directly to speed things up.... FINISH LATER . new node set node=$get(^DD(FileNum,Field,0)) . set FieldInfo("SPECIFIER")=$piece(node,"^",2) . set FieldInfo("LABEL")=$piece(node,"^",1) . set FieldInfo("MULTIPLE-VALUED")=(+FieldInfo("SPECIFIER")>0) . if FieldInfo("SPECIFIER")["W" set FieldInfo("TYPE")="WORD-PROCESSING" . else if FieldInfo("SPECIFIER")["D" set FieldInfo("TYPE")="DATE" . else if FieldInfo("SPECIFIER")["F" set FieldInfo("TYPE")="FREE TEXT" . else if FieldInfo("SPECIFIER")["P" set FieldInfo("TYPE")="POINTER" . else if FieldInfo("SPECIFIER")["N" set FieldInfo("TYPE")="NUMERIC" . else if FieldInfo("SPECIFIER")["S" set FieldInfo("TYPE")="SET" . else set FieldInfo("TYPE")=FieldInfo("SPECIFIER") set FldType=FieldInfo("SPECIFIER") if $data(Fields("TAG NAME",Field))#10>1 set Label=Fields("TAG NAME",Field) else set Label=FieldInfo("LABEL") if $get(FieldInfo("MULTIPLE-VALUED"))=1 do . if $get(FieldInfo("TYPE"))="WORD-PROCESSING" do . . new TMGWP,TMGMsg,result . . set result=$$ReadWP^TMGDBAPI(FileNum,IENS,Field,.TMGWP) . . if result=1 do . . . new i set i=$order(TMGWP("")) . . . if i="" quit . . . if Flags["i" write $get(IndentS) . . . new exFn set exFn="do "_FWriter_"(Label,"""_$$QtProtect^TMGSTUTL(Field)_""","""_FieldInfo("TYPE")_""",0)" . . . xecute exFn . . . write ! ;"so first will be on a separate line . . . for do quit:(i="") . . . . new line set line=$get(TMGWP(i)) . . . . set line=$$CmdChStrip^TMGSTUTL(line) ;"shouldn't be needed!!! ??GT.M bug?? . . . . if Flags["i" write $get(IndentS)_IncIndent . . . . set exFn="do "_WPLWriter_"("""_$$QtProtect^TMGSTUTL(line)_""")" . . . . ;"WRITE exFn,! . . . . xecute exFn . . . . set i=$order(TMGWP(i)) . . . if Flags["i" write $get(IndentS) . . . set exFn="do "_FWriter_"(Label,"""_$$QtProtect^TMGSTUTL(Field)_""","""_FieldInfo("TYPE")_""",1)" . . . xecute exFn . else do ;"Other multiple (subfile) . . set SubFile=+FldType . . new AllSubRecs,tempField . . new ORoot,Node . . if $get(SRef)'="" set ORoot=SRef . . else set ORoot=$get(^DIC(FileNum,0,"GL")) . . if ORoot="" quit . . if AllFields set tempField="*" . . else set tempField=LastFileName . . set AllSubRecs=($data(Fields(tempField,"*"))>0)!($order(Fields(tempField,""))="") . . set Node=$piece($get(FieldInfo("StoreLoc")),";",1) . . if Node="" quit ;"skip computed fields . . if (+Node'=Node) set Node=""""_Node_"""" ;" enclose text indices with quotes . . set SRoot=ORoot_IEN_","_Node_"," ;"open root . . set CRoot=ORoot_IEN_","_Node_")" ;"closed root . . set SubRec=$order(@CRoot@(0)) . . if (SubRec'="")!(Flags["b") do . . . if Flags["i" write $get(IndentS) . . . new exFn set exFn="do "_FWriter_"("""_$$QtProtect^TMGSTUTL(Label)_""","""_$$QtProtect^TMGSTUTL(Field)_""","""_FieldInfo("TYPE")_""",0)" . . . xecute exFn . . . write ! . . . new IndS2 set IndS2=$get(IndentS)_IncIndent . . . if +SubRec>0 for do quit:+SubRec'>0 . . . . ;"descend into subfile (if allowed subrecord #) . . . . if (AllSubRecs)!($data(Fields(tempField,SubRec))>0) do . . . . . if $data(Fields(tempField,"Rec Exclude",SubRec))>0 quit . . . . . new SubIENS,SubFields,tempSR . . . . . if AllSubRecs set tempSR="*" . . . . . else set tempSR=SubRec . . . . . set SubIENS=SubRec_","_IENS . . . . . merge SubFields=Fields(tempField,tempSR) . . . . . if (AllFields)!($data(SubFields)=0) set SubFields("*")="" . . . . . if Flags["i" write $get(IndS2) . . . . . new exFn set exFn="do "_RWriter_"("_$$QtProtect^TMGSTUTL(SubRec)_",0)" . . . . . xecute exFn . . . . . do Write1Rec(SubFile,SubRec,.SubFields,Flags,SRoot,SubIENS,IndS2_IncIndent,.RWriter,.FWriter,.LWriter,.WPLWriter,.SavFieldInfo) . . . . . if Flags["i" write $get(IndS2) . . . . . new exFn set exFn="do "_RWriter_"("_$$QtProtect^TMGSTUTL(SubRec)_",1)" . . . . . xecute exFn . . . . set SubRec=$order(@CRoot@(SubRec)) . . . if Flags["i" write $get(IndentS) . . . set exFn="do "_FWriter_"("""_$$QtProtect^TMGSTUTL(Label)_""","""_$$QtProtect^TMGSTUTL(Field)_""","""_FieldInfo("TYPE")_""",1)" . . . xecute exFn else do ;"the usual case here... . new line set line="" . new CustXForm set CustXForm=$get(Fields("TRANSFORM",Field)) . if CustXForm'="" do . . new Pos,GRef,Node . . new FILE,FIELD,X,Y . . new IntValue set IntValue="" . . if $get(SRef)'="" set ORoot=SRef . . else set ORoot=$get(^DIC(FileNum,0,"GL")) . . if ORoot="" quit . . set Node=$piece($get(FieldInfo("StoreLoc")),";",1) . . if Node="" quit ;"skip computed fields . . if (+Node'=Node) set Node=""""_Node_"""" ;" enclose text indices with quotes . . set Pos=$piece($get(FieldInfo("StoreLoc")),";",2) . . set GRef=ORoot_IEN_","_Node_")" . . if +Pos>0 set IntValue=$piece($get(@GRef),"^",Pos) . . ;"Set up variables for use by transform code . . set FILE=FileNum . . set FIELD=+Field . . set X=IntValue . . set Y="" . . new $etrap set $etrap="set Y=""(Invalid custom transform M code!. Error Trapped.)"" set $etrap="""",$ecode=""""" . . xecute CustXForm . . set line=Y . else do . . new GetFlag set GetFlag="" . . if Flags["I" set GetFlag="I" . . set line=$$GET1^DIQ(FileNum,IENS,Field,GetFlag) . if (line="")&(Flags'["b") quit . if Flags["i" write $get(IndentS) . new exFn set exFn="do "_FWriter_"("""_$$QtProtect^TMGSTUTL(Label)_""","""_$$QtProtect^TMGSTUTL(Field)_""","""_FieldInfo("TYPE")_""",0)" . xecute exFn . set exFn="do "_LWriter_"(.line)" . xecute exFn ;"write line . if Flags["i" write $get(IndentS) . set exFn="do "_FWriter_"("""_$$QtProtect^TMGSTUTL(Label)_""","""_$$QtProtect^TMGSTUTL(Field)_""","""_FieldInfo("TYPE")_""",1)" . xecute exFn W1FDone quit WriteRLabel(IEN,Ender) ;"Purpose: To actually write out labels for record starting and ending. ;" IEN -- the IEN (record number) of the record ;" Optional extra informat: ;" IEN(tag)=value ;" IEN(tag2)=value2 ;" If provided, will be added to output as follows: ;" ;" Ender -- OPTIONAL if 1, then ends field. ;"Results: none. ;"Note: This is a separate function so that a different callback function can replace it if +$get(Ender)>0 write "",! else do . write "",! quit WriteFLabel(Label,Field,Type,Ender) ;"Purpose: This is the code that actually does writing of labels etc for output ;"Input: Label -- OPTIONAL -- Name of label, to write after 'label=' ;" Field -- OPTIONAL -- Name of field, to write after 'id=' ;" Type -- OPTIONAL -- Typeof field, to write after 'type=' ;" Ender -- OPTIONAL if 1, then ends field. ;"Results: none. ;"Note: This is a separate function so that a different callback function can replace it ;"To write out or if +$get(Ender)>0 do . write "",! else do . write "" quit WriteLine(Line) ;"Purpose: This is the code that actually does writing of labels etc for output ;"Input: Line -- the line of text to write out. ;"Results: none ;"Note: This is a separate function so that a different callback function can replace it set Line=$$SYMENC^MXMLUTL(Line) write "",Line,"",! quit ConvertLabel(Label) ;"Note: This function is no longer being used... ;"To convert the XML tag into an acceptible format for XML ;" new i new result set result="" for i=1:1:$length(Label) do . new ch set ch=$ascii($extract(Label,i)) . if ((ch>64)&(ch<91))!((ch>96)&(ch<123)) do quit . . set result=result_$char(ch) . if (ch=32) set result=result_"_" . else do . . set result=result_"x" quit result