sassas-stored-process

SAS Stored Process STP web: How to reference html file for file _webout instead of put statements?


So I've seen various pages that inform SAS Stored Process users creating stored process web pages how to do something like:

https://support.sas.com/documentation/cdl/en/stpug/62758/HTML/default/viewer.htm#p0q383asmm4bejn1i7z4q7iv5eke.htm

data _null_;
file _webout;
put '<HTML>';
put '<HEAD><TITLE>Hello World!</TITLE></HEAD>';
put '<BODY>';
put '<H1>Hello World!</H1>';
put '</BODY>';
put '</HTML>';
run;

The put HTML statements are nice and a quick way to get HTML to the page, but I'm noticing my HTML using put is getting quite messy and not maintainable.

How can I reference an external HTML file instead? I do have some SAS macros that I reference in the HTML put statements so I'm not sure if those would resolve in the external html but still interested to see a working example of referencing an external HTML file in a stored process.

UPDATE - My Example Program

In this put HTML I am just writing a form to the web page with some data populated in a drop down. I would just like to call this as raw html from an external HTML file while still resolving the SAS code embedded in the HTML like macro variable references.

%macro test;

proc sql;        
create table eqmtid_name as        
      select distinct EQMT_ID        
      from library.joined_data;        

%let neqmtid = &sqlobs;        
quit;        

data _null_;        
set eqmtid_name;        
 suffix=put(_n_,8.);        
 call symput(cats('EQMTID',suffix), EQMT_ID);        
run;    

data _null_;

file _webout;
put '<script type="text/javascript">document.body.innerHTML = "";</script>';  
put '<HTML>';  
put '<head>';  
put '<script type="text/javascript">'; 
put 'document.addEventListener("DOMContentLoaded", function initialize() {'; 
put '   var svgs = document.getElementsByTagName("svg");'; 
put '   for (i = 0; i < svgs.length; ++i) {'; 
put '    e = svgs[i];'; 
put '    e.removeAttribute("height");'; 
put '    e.removeAttribute("width");'; 
put '    e.setAttribute("width","80%");'; 
put '   }'; 
put '   '; 
put '});'; 
put '</script>'; 
put '</head>';  
put '<BODY onload="initialize()">';   
put '<HEADER class="pageheader">'; 
put '<TABLE>'; 
put '<tr>';
put '<td>'; 
put '<div class="divcenter">Header Text</div>'; 
put '</td>'; 
put '</tr>'; 
put '</TABLE>'; 
put '</HEADER>'; 
put '<FORM NAME="sub" METHOD="GET" ACTION="/SASStoredProcess/do">';            
put '<INPUT TYPE="HIDDEN" NAME="_program" SIZE="100" VALUE="/Company/IT/Development/APP/stp_program">';         
put '<INPUT TYPE="CHECKBOX" NAME="_debug" VALUE="log">Show SAS Log <br>';       
put '<TABLE>';        
put '<tr>';        
put '<td>';        
put '<label class="formitem">Equipment ID:</label>';        
put '</td>';        
put '<td>';        
put '<select class="formitem styleinput" name="EQMTID">' /        
   '<option value=""></option>' /        
   %do i = 1 %to &neqmtid; /        
   "<option value = %bquote(")%left(%trim(&&EQMTID&i))%bquote(") >&&EQMTID&i</option>" /        
   %end; /        
   '</select>';        
put '</td>';        
put '</TABLE>';        
put '<br>'; 
put '<TABLE>';  
put '<tr>'; 
put '<td>'; 
put '<INPUT class="button" class="formitem" TYPE="SUBMIT" VALUE="Search"><br>';       
put '</td>'; 
put '</FORM>'; 
put '<FORM NAME="download" TARGET="_blank" METHOD="GET" ACTION="/SASStoredProcess/do">';            
put '<INPUT TYPE="HIDDEN" NAME="_program" SIZE="100" VALUE="/Company/IT/Development/APP/export_data_stp">';         
put '<td>'; 
put '<INPUT class="button" class="formitem" TYPE="SUBMIT" VALUE="Download"><br>';       
put '</td>'; 
put '</FORM>'; 
put '</tr>'; 
put '</TABLE>'; 
put '</BODY>';             
put '</HTML>';   

run;

%mend;

%test;

UPDATE SOLVED

Thanks to the example Joe outlined below, this is what I had to code to make this work... in SAS Code:

filename htmlfile "/sasdata/IT/APP/file.html";

proc stream outfile=_webout;
begin
&streamdelim; %include htmlfile;
;;;;
run;

Note: in your html file if you have macro statements like %DO loops, you might get an error like "Error: The %DO statement is not valid in open code". In order to resolve that error I included a macro wrapper in the html file around that statement like this:

<select class="formitem styleinput" name="EQMTID">       
<option value=""></option>

%macro doeqmt;

%do i = 1 %to &neqmtid;    
"<option value = %bquote(")%left(%trim(&&EQMTID&i))%bquote(") >&&EQMTID&i</option>"
%end;

%mend;
%doeqmt;

</select>

Solution

  • Depending on your exact details, there are a few ways to do this, but the simplest two are either read the HTML into a data step (in a character variable, one per line) and then putting it back out again (this is better if you need to perform some modifications on it), or as Tom suggested you can use PROC STREAM if you don't need to modify it much or if you can insert macro variables (or macros) in the raw HTML pre-file.

    PROC STREAM is pretty simple. Imagine I have a hello world type file, in c:\temp\helloworld.html

    <html>
      <header>
        <title>My Example Page</title>
      </header>
      <body>
        <h1> Hello, World </h1>
      </body>
    </html>
    

    Then I could write this short program:

    filename htmlfile "c:\temp\helloworld.html";
    filename outfile  "c:\temp\stream.html";
    proc stream outfile=outfile;
    begin
    &streamdelim readfile htmlfile;
    ;;;;
    run;
    

    And I'd now have a new file, stream.html, with the same contents. And with any macro variables or macros in it resolved.

    For example, let's change it just slightly:

    Input:

    <html>
      <header>
        <title>My Example Page</title>
      </header>
      <body>
        <h1> &mystring. </h1>
      </body>
    </html>
    

    Output, noting the new %let:

    filename htmlfile "c:\temp\helloworld.html";
    filename outfile  "c:\temp\stream.html";
    
    %let mystring = Hello, World;
    proc stream outfile=outfile;
    begin
    &streamdelim readfile htmlfile;
    ;;;;
    run;
    

    Note that it resolves the macro variable for us.

    You can just change the outfile to _WEBOUT and you should get what you're hoping for, if I understand you right.