@texasmfp I consider it most of the time as easier (especially when it comes to debugging) to create a table for data driven code generation and then use this data to generate and execute the actual code.
Below a working example generating the http call you shared.
data driver;
infile datalines truncover dsd dlm=',';
input url:$300. param_name:$50. param_val:$50.;
datalines;
http://dataservices.imf.org/REST/SDMX_xml.svc/CompactData/IFS/M.IN.PCPI_IX.,startPeriod,2019
http://dataservices.imf.org/REST/SDMX_xml.svc/CompactData/IFS/M.IN.PCPI_IX.,endPeriod,2024
;
proc sort data=driver;
by url;
run;
/* create temporary file for generated code */
filename codegen temp;
data _null_;
stop;
file codegen;
run;
data _null_;
/* write generated code to temp file */
/* file codegen;*/
/* for development: write generated code to print destination */
file print;
set driver;
by url;
length url_all $1000;
retain url_all;
if cmiss(param_name, param_val)=0 then url_all=catx('&',url_all,catx('=',urlencode(strip(param_name)),urlencode(trim(param_val))));
if last.url then
do;
n+1;
url_all=catx('?',url, url_all);
put
'%let ind=' n z4. ';' /
'%let out_path=%sysfunc(pathname(work))\out_&ind..xml;' /
'filename out_&ind "&out_path";' /
'proc http ' /
" url='" url_all +(-1) "' " /
' method="get" ' /
' out=out_&ind' /
' clear_cache ' /
' ; ' /
'run; ' /
;
put
'filename map temp;' /
'libname out_&ind xmlv2 "&out_path" automap=replace xmlmap=map;' /
;
call missing(url_all);
end;
run;
/* execute generated code */
%include codegen / source2;
With above script the following code gets generated:
%let ind=0001;
%let out_path=%sysfunc(pathname(work))\out_&ind..xml;
filename out_&ind "&out_path";
proc http
url='http://dataservices.imf.org/REST/SDMX_xml.svc/CompactData/IFS/M.IN.PCPI_IX.?startPeriod=2019&endPeriod=2024'
method="get"
out=out_&ind
clear_cache
;
run;
filename map temp;
libname out_&ind xmlv2 "&out_path" automap=replace xmlmap=map;
...and of course how you create the driver table is up-to-you and if there is some logic to the parameters then you can of course also generate the rows instead of having to define them explicitly as data.
Here a variation of above with a bit more logic to create the driver table and generating two http calls.
data sites;
infile datalines truncover dsd dlm=',';
input site_id url:$300.;
datalines;
1,http://dataservices.imf.org/REST/SDMX_xml.svc/CompactData/IFS/M.IN.PCPI_IX.
;
run;
data parameters;
infile datalines truncover dsd dlm=',';
input site_id param_group param_name:$50. param_val:$50.;
datalines;
1,1,startPeriod,2019
1,1,endPeriod,2024
1,2,startPeriod,2020
1,2,endPeriod,2021
;
data driver;
merge sites(in=ina) parameters;
by site_id;
if ina;
run;
proc sort data=driver;
by site_id param_group;
run;
/* create temporary file with generated code */
filename codegen temp;
data _null_;
stop;
file codegen;
run;
data _null_;
/* write generated code to temp file */
file codegen;
/* for development: write generated code to print destination */
/* file print;*/
set driver;
by site_id param_group;
length url_all $1000;
retain url_all;
if cmiss(param_name, param_val)=0 then url_all=catx('&',url_all,catx('=',urlencode(strip(param_name)),urlencode(trim(param_val))));
if last.param_group then
do;
n+1;
url_all=catx('?',url, url_all);
put
'%let ind=' n z4. ';' /
'%let out_path=%sysfunc(pathname(work))\out_&ind..xml;' /
'filename out_&ind "&out_path";' /
'proc http ' /
" url='" url_all +(-1) "' " /
' method="get" ' /
' out=out_&ind' /
' clear_cache ' /
' ; ' /
'run; ' /
;
put
'filename map temp;' /
'libname out_&ind xmlv2 "&out_path" automap=replace xmlmap=map;' /
;
call missing(url_all);
end;
run;
/* execute generated code */
%include codegen / source2;
... View more