Example 4: Creating and Using a User-Defined Table Definition Template

Features:

PROC TEMPLATE

FILE PRINT ODS statement::
COLUMNS= suboption:
FORMAT= suboption
DYNAMIC= suboption
GENERIC= suboption
TEMPLATE=
PUT _ODS_ statement::
column pointer controls
line pointer controls
ODS destination: RTF

Details

This example shows how to do the following:
  • create a simple user-defined template (table definition) with PROC TEMPLATE
  • use a simple user-defined template in the DATA step
  • use pointer controls in the PUT _ODS_ statement

Program: Creating the User-Defined Table Definition (Template)

proc template;
define table phonelist;
      column name phone;
      dynamic colheader;
   define name;
      generic=on;
      header=colheader;

      style=data{fontstyle=italic fontsize=5};
   end;

   define phone;
      header='Telephone';
      style=datafixed;
   end;
end;
run;
ods html close;
ods rtf body='your_rtf_file.rtf';
title 'New Subscriber Telephone List';
proc format;
   picture phonenum .='Not available'
                other='0000)000-0000' (prefix='(');
run;
data phones;
   length first_name $20 last_name $25;
   input first_name $ last_name $ business_phone home_phone;
   datalines;
Jerome Johnson 9193191677 9198462198
Romeo Montague 8008992164 3609736201
Imani Rashid 5088522146 5083669821
Palinor Kent . 9197823199
Ruby Archuleta . .
Takei Ito 7042982145 .
Tom Joad 2099632764 2096684741
;
proc sort data=phones;
   by last_name;
run;
data
_null_;
    set phones;
file print
ods=(template='phonelist'
           columns=
                         (name=last_name
                           (generic=on
                            dynamic=(colheader='Last Name'))
                          name=first_name
                           (generic=on
                            dynamic=(colheader='First Name'))
                          phone=business_phone
                            (format=phonenum.)
                          )
               );
if
(missing(business_phone)) then
   put _ods_ @3 home_phone;
else if (missing(home_phone)) then 
   put _ods_;
else
   put _ods_ / @3 home_phone;
run;
ods RTF close;

Program Description

Define the table definition PHONELIST. This PROC TEMPLATE step defines a table definition named PHONELIST. The template defines two columns: NAME and PHONE. The GENERIC=ON attribute defines the column for NAME as one that the DATA step can use for multiple variables. The column definition uses dynamic headers; that is, a variable that uses this column definition takes the value of the header at run time from the DATA step that uses this template. Thus, each variable can have a different column heading. The STYLE= attribute specifies that the style element DATA be used as the basis for generating the data in this column. The font face and font size that DATA normally uses are replaced by the ones that are specified in the STYLE= attribute. The header for PHONE is hardcoded as Telephone. The STYLE= attribute specifies a style element to use for the data in this column.
proc template;
define table phonelist;
      column name phone;
      dynamic colheader;
   define name;
      generic=on;
      header=colheader;

      style=data{fontstyle=italic fontsize=5};
   end;

   define phone;
      header='Telephone';
      style=datafixed;
   end;
end;
run;
Specify that you do not want to produce the default HTML output. The ODS HTML CLOSE statement closes the HTML destination to conserve resources. The HTML destination is open by default when you open your SAS session.
ods html close;
Specify that you want the output formatted in RTF. The ODS RTF statement opens the RTF destination and creates RTF output for use by Microsoft Word. Subsequent output objects are sent to the body file.
ods rtf body='your_rtf_file.rtf';
Specify a title. The TITLE statement provides a title for the output.
title 'New Subscriber Telephone List';
Create a format for telephone numbers. PROC FORMAT creates a user-defined format for telephone numbers.
proc format;
   picture phonenum .='Not available'
                other='0000)000-0000' (prefix='(');
run;
Create the PHONES data set. The data set PHONES contains names and their corresponding phone numbers. Some observations contain missing values for the business or home phone numbers.
data phones;
   length first_name $20 last_name $25;
   input first_name $ last_name $ business_phone home_phone;
   datalines;
Jerome Johnson 9193191677 9198462198
Romeo Montague 8008992164 3609736201
Imani Rashid 5088522146 5083669821
Palinor Kent . 9197823199
Ruby Archuleta . .
Takei Ito 7042982145 .
Tom Joad 2099632764 2096684741
;
Sort the PHONES data set by last name. PROC SORT sorts the data set PHONES by LAST_NAME and replaces the original data set with the sorted data set.
proc sort data=phones;
   by last_name;
run;
Begin a DATA step that does not create an output data set. Read an observation from the PHONES data set. Using _NULL_ saves computer resources because it prevents the DATA step from creating an output data set.
data
_null_;
    set phones;
Request that ODS output be created and use the template named PHONELIST. The combination of the fileref PRINT and the ODS option in the FILE statement sends the results of the DATA step to ODS. ODS creates an output object and binds it to the PHONELIST template. Only RTF output is created because only the RTF destination is open. The TEMPLATE= suboption tells ODS to use the template PHONELIST, which was created previously in the PROC TEMPLATE step.
file print
ods=(template='phonelist'
Place variable values in columns. The COLUMNS= suboption places values of variables into columns that are defined in the template. Values for both the LAST_NAME and FIRST_NAME variables are written to columns that are defined as NAME in the template. The GENERIC=ON suboption must be set in both the template and the ODS= option in order for you to use a column definition for more than one column. The value of the variable BUSINESS_PHONE is placed in a column that is defined as PHONE. The DYNAMIC= suboption assigns a value to the variable COLHEADER. This value is passed to the template when the output object is created, and the template uses it for the column heading. Thus, even though the variables use the same column definition from the template, the columns in the output object have different column headings. The FORMAT= suboption assigns the format PHONENUM. to the column named PHONE.
           columns=
                         (name=last_name
                           (generic=on
                            dynamic=(colheader='Last Name'))
                          name=first_name
                           (generic=on
                            dynamic=(colheader='First Name'))
                          phone=business_phone
                            (format=phonenum.)
                          )
               );
The following IF/THEN-ELSE statements execute a different PUT _ODS_ statement based on the specified conditions.If BUSINESS_PHONE contains missing values, then the PUT statement writes values for LAST_NAME, FIRST_NAME, and BUSINESS_PHONE (the columns that are defined in the ODS= option) into the output buffer. The PUT statement then writes the value for HOME_PHONE in column 3, overwriting the missing value of BUSINESS_PHONE. If HOME_PHONE contains a missing value, then the PUT statement simply writes values for LAST_NAME, FIRST_NAME, and BUSINESS_PHONE to the buffer. Finally, if both phone numbers have values, then the PUT statement writes values for LAST_NAME, FIRST_NAME, and BUSINESS_PHONE to the buffer in the first line. SAS then goes to the next line (as directed by the line pointer control / ) and writes the value of HOME_PHONE in the third column of the next line.
if
(missing(business_phone)) then
   put _ods_ @3 home_phone;
else if (missing(home_phone)) then 
   put _ods_;
else
   put _ods_ / @3 home_phone;
run;
Close the RTF destination so that you can view the output. The ODS RTF statement closes the RTF destination and all the files that are associated with it. You must close the destination before you can view the output in Microsoft Word. Also, closing the output prevents all subsequent ODS jobs from automatically producing RTF output.
ods RTF close;

RTF Output

RTF Output Viewed with Microsoft Word
RTF Output Viewed with Microsoft Word