1

I want to put a html-generating macro function inside a html document and write the html document to _webout via a data step that uses resolve, see below pseudocode for details. However when the output of the html_generating_macro function exceeds 32767 characters, it gets truncated. As I understand it, the limitation is within the datastep variable text. How can I overcome this limitation and get the output of resolve (and the html_generating_macro) to _webout?

data _null_;
file _webout;
length text $32767;
retain text;
infile index.html flowover end=last;
input;
text = resolve(_infile_);
put text;

run;


%macro html_generating_macro();

%do i=1 %to 10000;
some html code
%end;

%mend;
<html>
<body>
%html_generating_macro
</body>
</html>

2 Answers2

3

As Tom says in comments, PROC STREAM is the gold standard here, and largely does what you're doing.

If you're not able to use PROC STREAM, then you can break it up. What you'd want to do is write your html generating macro in such a way that it wrote to _WEBOUT itself, rather than returning text, or failing that, so that it was self-aware of length and returned 32000 bytes at a time.

This latter is a common way APIs work; for example, an API I use returns only 100 records at a time, but I call it for 2000 or so. What they do typically is return the first 100 records, and either a URL for the next 100 or a token that is sort of a bookmark for where they left off.

So you'd write something like...

%macro html_generating_macro(startat=0);
 %global returnparm;

 %if &startat ne 0 %then %do;
   (code to skip to startat)
 %end;
 ... stuff ...
 %if &calculated_length_var gt 32000 %then %do;
   %let returnparm = %eval(&startat. + 32000);  *or, if it has to cut off at particular spots, calculate how much you are sending;
 %end;
 %else %do;
    %let returnparm = 0;
 %end;
%mend html_generating_macro;

Something like that, though the 'skip to startat' and the bit at the end is a bit more complicated, depending on what you're actually doing. Main idea is to have the ability to start at an arbitrary spot, and the ability to know when you are at a particular length and stop there, returning the spot you're at. Then the next call returns that to be used as the next startat value.

Joe
  • 62,789
  • 6
  • 49
  • 67
  • PROC STREAM did the trick, thanks. Found this post which might be useful for someone with a similar problem https://stackoverflow.com/questions/46939235/sas-stored-process-stp-web-how-to-reference-html-file-for-file-webout-instead – wasserslasken Jan 22 '22 at 12:01
  • PROC STREAM works well, but if I use %INCLUDE, the formatting disappear, causing problems with linebreaks. Using readfile keeps the formatting but does not resolve macro variables/functions. Is it possible to both keep formatting and resolve macros? – wasserslasken Feb 09 '22 at 13:38
  • If this is going to a web destination, can you add manual `
    ` or similar?
    – Joe Feb 09 '22 at 15:43
  • The problem is not the final formatting but the formatting of the code. Ex. if linebreaks are ignored, then this will be one line and the comment will mess upp the javascript: `` – wasserslasken Feb 09 '22 at 20:46
1

This might work for a very basic page, but proc stream is subpar if you're looking to build a more complex application.

If you really must embed HTML content in SAS code, far better to compile it outside SAS and keep the web content fully separated from your SAS programs in source. Compiling the frontend in this way is a concept we term "streaming apps".

A demonstration of this is available here: https://sasapps.io/sas-streamed-apps

Disclaimer - my team built the (open source) framework that makes this approach possible.

More examples of streaming apps here: https://sasjs.io/apps/

Allan Bowe
  • 12,306
  • 19
  • 75
  • 124