Macro Xtab2htm Freq cross-tab to html

From sasCommunity
Jump to: navigation, search

%XTAB2HTM: macro using ODS to convert proc FREQ cross-tabulation to HTML with a Table of Contents and back buttons

Author: Ronald_J._Fehd

Programs

Macro Xtab2htm

 /*   Name: xtab2htm.sas
  location: <UNC>\SAS-site\macros
DESCRIP : FREQ CrossTabulation to HTML
          write ODS file INDEX.HTML & pairs: *XTAB.HTML + *LIST.HTML
USAGE   : %XTAB2HTM(DATA,VAR1,VAR2,ID(S),DIRECTORY-PATH);
          %XTAB2HTM(TEST,_NAME_,TEXT,ID,C:\TEMP\);
PROCESS : 0. SORT and create copy: DETAILS
          1. FREQ of VAR1 to output data set: INDEX
          2. add html anchors/links to INDEX
          3. write ODS file INDEX.html
          4. list processing: make subsets, write HTMWRITE
KEYWORDS: list-processing HTML ODS anchor href word
AUTHOR  : Ronald J. Fehd
NOTE    : illustration of the Writing for Reading SAS(r) Style Sheet. */
%MACRO XTAB2HTM /*- - - - - - - - - - - - - - - - - - - - - - - - - - */
         (DATA  /* data set name                                      */
         ,VAR1  /* proc FREQ cross-table first  var                   */
         ,VAR2  /* proc FREQ cross-table second var                   */
         ,ID    /* identifier(s)                                      */
         ,PATH  /* destination of HTML files                          */
         ,HTML    =htm  /* file extension in(htm,html)                */
         ,INDEX   =index/* name of top-level file in (home,index)     */
         ,LIST    =list /* suffix of PROC Print DETAILS file          */
         ,XTAB    =xTab /* suffix of proc FREQ cross-tab file         */
         ,TITLEN  =3    /* title line number for Table of Contents    */
         ,TESTING =0    /* enable testing msgs and prints             */
);/*change notes  - - - - - - - - - - - - - - - - - - - - - - - - - - **
RJF2 00May24 runs OK w/numerics with number-to-char conversion notes
RJF2 00Jun30 polishing: changed build of call execute data set
**. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
%let TESTING = &Testing or %sysfunc(getoption(mprint)) eq MPRINT;
%*0;
proc SORT data =  &DATA.
          (keep=  &VAR1. &VAR2. &ID.)
          out  =  DETAILS;
          by      &VAR1. &VAR2. &ID.;
 
%*1;
proc FREQ data =  DETAILS;
          tables  &VAR1.
          /out =  INDEX
          %IF not &TESTING %THEN %DO;
                  noprint
                  %END;
          ;
%local LEVELWID;/**order of magnitude of number of data sets to write
      ,LEVELWID=1 max: 9 levels LEVELWID=2 max:99 levels              */
data _NULL_;
    if 0 then set INDEX nobs=Nobs;
    call symput("LEVELWID",compress(length(compress(put(Nobs,32.)))));
stop;
run;
 
%if &Testing. %then %put LEVELWID<&LEVELWID>;
%*2 add links to FREQ:INDEX of &VAR1.;
data INDEX;
     attrib Ndx&VAR1. length= $ 200 label="&VAR1. summary"
            NdxCount  length= $ 200 label="&VAR1. count"
            FileName  length= $ %eval(1 + &LEVELWID.)
            VarLabel  length= $  40 label="Var Label";
     retain FileNmbr 0 VarLabel '';
     drop   FileNmbr  ;
 
do until(EndoFile);
   set    INDEX end = EndoFile;
   call   label(&VAR1.,VarLabel);
   FileNmbr +1;
   FileName = '_' !! put(FileNmbr,z&LEVELWID..);
   %*expected: <a href ="VARNAMExTab.html"> VARNAME </a>;
   Ndx&VAR1.= '<a href ="' !! FileName       !! "&XTAB..&HTML." !! '">'
                           !! &VAR1.         !! '</a>';
   NdxCount = '<a href ="' !! FileName       !! "&LIST..&HTML." !! '">'
                           !! put(Count,32.) !! '</a>';
   output;
   end;
stop;
run;
%IF &TESTING %THEN %DO;
    PROC Print data = INDEX;
               title3 Index;
    %END;
run;
*3 write INDEX.html;
ods listing close;
ods  html  body  =  "&PATH.&INDEX..&HTML.";
 
PROC Print data  =  INDEX label
           split =  ' ';
           format   Percent 5.1;
           var      Ndx: Percent;*Count;
           sum           Percent Count;
run;
ods html close;
ods listing;
 
/*4 write: 1. data set list:         DATA
                                     _1
                                     _2
                                     ;set DETAILS;
           2. subset output:         if Var = '<value1>' then output _1;
                                     if Var = '<value2>' then output _2;
                                     RUN;
           3. HTML         :         %HTMWRITE(_1,. .);
                                     %HTMWRITE(_2,. .); . . . . . . . */
DATA _NULL_;
     file   PRINT;
 
*4.1 write data set list;
call execute('data ');
 
do until(EndoFile);
   set INDEX(keep  = FileName) end = EndoFile;
   call execute(FileName);
   end;
 
*DATA closure, write set statement;
call execute(';set DETAILS;');
 
*reset for next loop;
EndoFile = 0;
 
%*4.2 write subset output statements;
do until(EndoFile);
   set INDEX(keep = &VAR1. FileName) end  = EndoFile;
   call execute("if &VAR1.='"
               !! trim(&VAR1.)
               !! "' then output "
               !! FileName !! ';');
   end;
*execute make of subsets;
call execute('RUN;');
 
*reset for next loop;
EndoFile = 0;
 
%*4.3 HTMWRITE(. .);
do until(EndoFile);
   set INDEX(keep = &VAR1. FileName VarLabel)
       end  = EndoFile;
   call execute('%HTMWRITE(data='
               !! FileName !! ',label='
               !! trim(VarLabel)
               !! ",var1=&VAR1.,var2=&VAR2.,path=&PATH.)");
   end;
stop;
run;
%mend xtab2htm;
 
%MACRO htmwrite
         (data  =/* data set name                    */
         ,label =/* data label: variable value       */
         ,var1  =/* proc FREQ cross-table first  var */
         ,var2  =/* proc FREQ cross-table second var */
         ,path  =/* destination of HTML files        */
         );/*this macro called by XTAB2HTM
NOTE: called via call execute: must have zero complexity:
                               NO call symput nor %IF
assumption: data set name is a subset
 data set containing only VAR1 values equal to level# of data set name
output: two HTML files
1. proc FREQ : cross-table           name: VARxTab
2. proc PRINT: detail list: see IDs  name: VARlist
note: references to: HTML INDEX LEVELWID LIST XTAB TITLEN
      these are local to XTAB2HTM
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
proc FREQ data  =  &DATA.;
          label   &VAR2.="&LABEL.";
          tables  &VAR2.
                / noprint list missing nocum
          out   = TBL_CONTENTS;
 
/*process TBL_CONTENTS: add anchor-href and -names: goto labels
                   <who> is the label, aka fragment identifier
<a href="index.html#who">What's That?</a>
<a href=          "#who">What's That?</a>
<a name=           "who">What's That?</a> * . . . . . . . . . . . . . */
 
DATA TBL_CONTENTS;
     attrib Link   length = $200 label = "&LABEL."
            ToC    length = $200 label = "&LABEL."
            Suffix length = $200
            Prefix length = $  9;%*123456789;
     *dQuote open           .;
     retain Prefix '<a href="'
            Row 0;
     drop   Row  ;
 
do until(EndoFile);
   set    TBL_CONTENTS end = EndoFile;;
   Row    +1;
   Suffix =  '#lvl'
          !! compress(put(Row,32.)) !! '">'  %*dQuote close;
          !! trim(&VAR2.) !! '</a>';
   ToC    =  Prefix !! Suffix;
   Link   =  Prefix !! "&DATA.&LIST..&HTML." %*double dots: fileref.ext;
                    !! Suffix;
   output;
   end;
stop;
run;
 
DATA &DATA.;
     attrib   Label length = $200;
     retain   Level 0;
     drop     &VAR2.;
 
do until(EndoFile);
   set      &DATA. end = EndoFile;
   by       &VAR2.;
   if first.&VAR2. then do;
      Level + 1;
      *dQuote open    .;
      Label = '<a name="lvl'
           !! compress(put(Level,32.))
           !! '">'
           %*  ^ dQuote close;
           !! trim(&VAR2.) !! '</a>';
      end;
   else                     Label = &VAR2.;
   output;
   end;
stop;
run;
ods listing close;
ods html  body = "&PATH.&DATA.&XTAB..&HTML.";
FOOTNOTE  '<a href ="' "&DATA.&XTAB..&HTML." '">top of file  </a>'
 '&nbsp;' '<a href ="'      "&INDEX..&HTML." '">back to index</a>';
%*&nbsp:  No BackSPace;
 
PROC Print data = TBL_CONTENTS   label;
           var    Link Count Percent;
           sum         Count Percent;
run;
ods html close;
 
ods html  body = "&PATH.&DATA.&LIST..&HTML.";
FOOTNOTE  '<a href ="' "&DATA.&LIST..&HTML." '">top of file  </a>'
 '&nbsp;' '<a href ="'      "&INDEX..&HTML." '">back to index</a>';
 
TITLE&TITLEN. "Table of Contents";
PROC Print data = TBL_CONTENTS label;
           var    ToC  Count Percent;
           sum         Count Percent;
run;
           TITLE&TITLEN.;
PROC Print data   = &DATA.
            (drop = &VAR1.)
                    label;
           label    Label ="&LABEL.";
           by       Level;
           id       Level;
run;
footnote;
ods html close;
ods listing;
%* . . . . . . . . . . . . . . . . . . . . .HTMWRITE;
%mend htmwrite;

Test Data

 /*TEST DATA ************************* enable w/slash at end of line: **/
DATA TEST;
*label _Name_ ='text variable';%*enable to use label instead of varname;
infile CARDS;input @ 1 ID     $char4.      @ 1 Nmbr        1.
                   @ 6 _Name_ $char8.      @15 Text   $char20.;   cards;
0811 TEST     TEST PERFORMED DAILY
0811 CODENONT TEST PERFORMED DAILY
0811 CODENONT TEST PERFORMED DAILY
2541 CODENONT TEST NOT PERFORMED I
4591 CODENONT TEST NOT PERFORMED I
9951 CODENONT TEST ONLY PERFORMED
7251 PRCNAMET ABBOT AXSYM HIV-1/HI
9941 PRCNAMET ABBOTT AXSYM
3631 PRCNAMET ABBOTT AXSYM
6661 PRCNAMET ABBOTT AXSYM
2771 PRCNAMET ABBOTT AXSYM
1422 PRCNAMET ABBOTT AXSYM HIV-1/H
2061 PRCNAMET ABBOTT AXSYM HIV-1/H
3961 PRCNAMET ABBOTT AXSYM HIV-1/H
1321 PRCNAMET ABBOTT AXSYM HIV1/HI
;%*run only one test at a time: character or numeric;
%XTAB2HTM(TEST,_NAME_,TEXT,ID,C:\TEMP\,TESTING=1);
%*XTAB2HTM(TEST,_NAME_,TEXT,ID,C:\TEMP\);
%*XTAB2HTM(TEST, Nmbr ,TEXT,ID,C:\TEMP\);%*numeric to char conversion;
 /*********************************************************************/

References

Ray Pass, (2000), You can get there from here and back again adding hot-link drill-down to %DS2HTM and %TAB2HTM Output SUGI 25 Advanced Tutorials # 17-25

--Ronald_J._Fehd macro.maven == the radical programmer 14:43, 1 July 2012 (EDT)