proc import
datafile="XXXXXXX\Exemple.xlsx"
out=RESULTAT
replace dbms=xlsx;
getnames=yes;
run;
%macro publi;
DATA _null_;
SET RESULTAT end=eof;
IF eof THEN
DO;
CALL SYMPUT('nombre',put(_N_,8.));
END;
run;
%do i=1 %to &nombre.;
/*****************************************************/
/*****Narratifs rélatids aus données calculées *******/
/*****************************************************/
data _NULL_;
set RESULTAT (obs=&i);
call symputx('PROFILE',PROFILE_NAME);
call symputx('PROFILE_OBJECTIVES',PROFILE_OBJECTIVES);
run;
OPTION NODATE NONUMBER;
OPTIONS PAPERSIZE=LETTER;
OPTIONS TOPMARGIN=0 in BOTTOMMARGIN=0 in LEFTMARGIN=0 in RIGHTMARGIN=0 in;
ODS NORESULTS;
ODS PDF FILE = "XXXXXXXX\Doc_&i..pdf" dpi=1800;
ODS ESCAPECHAR = "^";
data _NULL_;
declare odsout obj();
obj.layout_absolute(overrides :"borderwidth=0");
obj.line(style_attr: "bordercolor=blue", size:'0.8mm');
obj.table_start(name:
"table1",
label: "Notre Première Table",
overrides: "width=19 cm frame=void rules=none" );
obj.row_start();
obj.format_cell(data:
"NOM:" ,
overrides: "font_face=Calibri just=left font_weight=bold color=blue font_size=10pt");
obj.format_cell(data:
%sysfunc(quote(%superq(PROFILE))) ,
overrides: "just=left font_face=Calibri color=black font_size=10pt");
obj.row_end();
obj.row_start();
obj.format_cell(data:
"OBJECTIFS :" , overrides: "font_face=Calibri just=left font_weight=bold color=blue font_size=10pt width=2.5 cm");
obj.format_cell(data:
"&PROFILE_OBJECTIVES." ,overrides: "font_face=Calibri just=left color=black font_size=10pt width=15 cm");
obj.row_end();
obj.table_end();
obj.layout_end();
Run;
ODS PDF CLOSE;
%end;
%mend;
%publi;
Hi,
the
%sysfunc(quote(%superq(PROFILE)))
is giving the warning because it resolves to the following text
"ne devra représenter plus de 20 %du profil de gestion"
including double quotation symbols. So, since text is surrounded by double quotes, SAS[macro processor + wordscaner] scans it and it treats % as macro trigger.
Simpler example would be:
data _null_;
x = "%ABC";
y = '%EFG';
run;
in the log we will see warning for %ABC macro but not for %EFG.
If you would use version proposed by @Tom :
%sysfunc(quote(%superq(PROFILE), %str(%')))
the resolved text would be:
'ne devra représenter plus de 20 %du profil de gestion'
but with single quotation marks hence SAS[macro processor + wordscaner] won't treat % as macro trigger.
So Doc. references:
Hope it helps
Bart
No, you don't need double quotations. Documentation says that it doesn't have to be a text string but it could be a character variable (https://documentation.sas.com/?docsetId=odsadvug&docsetTarget=p12q0pykppxbz8n1200luexgbz4t.htm&docse...)
From the doc:
specifies the data to display.
'string' | specifies a text string. |
number | specifies a numeric value. |
character-variable | specifies the name of a character variable. The value of the character variable from the input data set is written to the output. |
numeric-variable | specifies the name of a numeric variable. The value of the numeric variable from the input data set is written to the output. |
See the code below which uses temporary_variables to solve the issue.
Btw.
this code can be done more efficient:
DATA _null_;
SET RESULTAT end=eof;
IF eof THEN
DO;
CALL SYMPUT('nombre',put(_N_,8.));
END;
run;
with:
DATA _null_;
CALL SYMPUTX('nombre',nobs);
stop;
SET RESULTAT nobs=nobs;
run;
Here is your code modified with temporary variables.
data RESULTAT;
PROFILE_NAME = 'ne devra représenter plus de 20 %du profil de gestion';
PROFILE_OBJECTIVES = "A B C D";
output;
run;
%macro publi;
DATA _null_;
SET RESULTAT end=eof;
IF eof THEN
DO;
CALL SYMPUT('nombre',put(_N_,8.));
END;
run;
%do i=1 %to &nombre.;
/*****************************************************/
/*****Narratifs rélatids aus données calculées *******/
/*****************************************************/
data _NULL_;
set RESULTAT (obs=&i);
call symputx('PROFILE',PROFILE_NAME);
call symputx('PROFILE_OBJECTIVES',PROFILE_OBJECTIVES);
run;
OPTION NODATE NONUMBER;
OPTIONS PAPERSIZE=LETTER;
OPTIONS TOPMARGIN=0 in BOTTOMMARGIN=0 in LEFTMARGIN=0 in RIGHTMARGIN=0 in;
ODS NORESULTS;
ODS PDF FILE = "%sysfunc(pathname(WORK))\Doc_&i..pdf" dpi=1800;
ODS ESCAPECHAR = "^";
data _NULL_;
/* TEMPORARY variables to replace MACRO variables */
_temporary_variable_1 = symget('PROFILE');
_temporary_variable_2 = symget('PROFILE_OBJECTIVES');
drop _temporary_variable_:;
declare odsout obj();
obj.layout_absolute(overrides :"borderwidth=0");
obj.line(style_attr: "bordercolor=blue", size:'0.8mm');
obj.table_start(name:
"table1",
label: "Notre Première Table",
overrides: "width=19 cm frame=void rules=none" );
obj.row_start();
obj.format_cell(data:
"NOM:" ,
overrides: "font_face=Calibri just=left font_weight=bold color=blue font_size=10pt");
obj.format_cell(data: _temporary_variable_1,
overrides: "just=left font_face=Calibri color=black font_size=10pt");
obj.row_end();
obj.row_start();
obj.format_cell(data:
"OBJECTIFS :" , overrides: "font_face=Calibri just=left font_weight=bold color=blue font_size=10pt width=2.5 cm");
obj.format_cell(data:
_temporary_variable_2 ,overrides: "font_face=Calibri just=left color=black font_size=10pt width=15 cm");
obj.row_end();
obj.table_end();
obj.layout_end();
Run;
ODS PDF CLOSE;
%end;
%mend;
%publi;
All the best
Bart
Let's spell the issue out in more detail. You want to use macro variables to generate a string constant in a call to some object method in a data step. If you add double quotes around the value then the macro processor will try to evaluate the string value for possible macro references (% and/or & characters). If you build the string with single quotes instead then the macro processor will ignore the value of the string constant so % and/or & will be left alone.
You are attempting to add the quotes after generating the macro variable. You have no need for the unquoted string in your current program. So instead you could just add the quotes into the value of the macro variable when you create it. Note there is no need to create the &ith macro variable &i times by processing observations 1 to &i. Just use the one observation.
data _null_;
set RESULTAT (firstobs=&i obs=&i);
call symputx('PROFILE',quote(trim(PROFILE_NAME),"'"));
call symputx('PROFILE_OBJECTIVES',quote(trim(PROFILE_OBJECTIVES),"'"));
run;
Then just use the macro variable, no need to add any quotes since they are already in the macro variable value.
obj.format_cell(data: &profile
...
obj.format_cell(data: &PROFILE_OBJECTIVES
...
But best method is to just skip making the macro variables and use the actual dataset variables by reading in the observation you want in the data step that is making the object calls.
data _null_;
set RESULTAT (firstobs=&i obs=&i);
declare odsout obj();
...
obj.format_cell(data: PROFILE_NAME
...
obj.format_cell(data: PROFILE_OBJECTIVES
...
Hello Tom,
Thank you, it works for the names, I don't have anymore the warning message.
I'm trying the suggested code with data _NULL_;
set RESULTAT (firstobs=&i obs=&i); , but it doesn't work:
Could you re-explain please how I can "skip making the macro variables and use the actual dataset variables by reading in the observation you want in the data step that is making the object calls." 🙂
Thank you very much!
Best regards,
Marie
proc import
datafile="XXX\Exemple.xlsx"
out=RESULTAT
replace dbms=xlsx;
getnames=yes;
run;
%macro publi;
/*****************************************************/
/*****Narratifs rélatids aus données calculées *******/
/*****************************************************/
OPTION NODATE NONUMBER;
OPTIONS PAPERSIZE=LETTER;
OPTIONS TOPMARGIN=0 in BOTTOMMARGIN=0 in LEFTMARGIN=0 in RIGHTMARGIN=0 in;
ODS NORESULTS;
ODS PDF FILE = "XXX\Doc_&i..pdf" dpi=1800;
ODS ESCAPECHAR = "^";
data _NULL_;
set RESULTAT (firstobs=&i obs=&i);
declare odsout obj();
obj.layout_absolute(overrides :"borderwidth=0");
obj.line(style_attr: "bordercolor=blue", size:'0.8mm');
obj.table_start(name:
"table1",
label: "Notre Première Table",
overrides: "width=19 cm frame=void rules=none" );
obj.row_start();
obj.format_cell(data:
"NOM:" ,
overrides: "font_face=Calibri just=left font_weight=bold color=blue font_size=10pt");
obj.format_cell(data:
quote(PROFILE) ,
overrides: "just=left font_face=Calibri color=black font_size=10pt");
obj.row_end();
obj.row_start();
obj.format_cell(data:
"OBJECTIFS :" , overrides: "font_face=Calibri just=left font_weight=bold color=blue font_size=10pt width=2.5 cm");
obj.format_cell(data:
PROFILE_OBJECTIVES ,overrides: "font_face=Calibri just=left color=black font_size=10pt width=15 cm");
obj.row_end();
obj.table_end();
obj.layout_end();
Run;
ODS PDF CLOSE;
%mend;
%publi;
You cannot use the function call, quote(PROFILE). You have to either have the literal string or the variable name.
Your variable name is PROFILE_NAME, not PROFILE.
So change that to just PROFILE_NAME.
You also seem to have removed your loop.
Formatting the code will make it much easier to read. I prefer not to waste line space with unneeded extra leading spaces. No need to indent every line inside of a macro definition. Make sure to place continuation characters and termination characters for multi-line statements at the beginning of the line instead of the end of the line so that they are easy for humans to scan for. Define the macro first and then start your actual executable code. Don't put tab characters into the code. Use the indent/tab features of your editor to insert a consistent number of spaces instead. Move static code outside of the DO loop. Define your local macro variables.
%macro publi;
/*****************************************************/
/*****Narratifs rélatids aus données calculées *******/
/*****************************************************/
%local i nobs ;
OPTIONS NODATE NONUMBER;
OPTIONS PAPERSIZE=LETTER;
OPTIONS TOPMARGIN=0 in BOTTOMMARGIN=0 in LEFTMARGIN=0 in RIGHTMARGIN=0 in;
ODS NORESULTS;
ODS ESCAPECHAR = "^";
data _null_;
call symputx('nobs',nobs);
stop;
set RESULTAT nobs=nobs;
run;
%do i=1 %to &nobs;
ODS PDF FILE = "XXX\Doc_&i..pdf" dpi=1800;
data _NULL_;
set RESULTAT (firstobs=&i obs=&i);
declare odsout obj();
obj.layout_absolute(overrides: "borderwidth=0");
obj.line(style_attr: "bordercolor=blue", size:'0.8mm');
obj.table_start(name: "table1"
,label: "Notre Première Table"
,overrides: "width=19 cm frame=void rules=none"
);
obj.row_start();
obj.format_cell(data: "NOM:"
,overrides: "font_face=Calibri just=left font_weight=bold color=blue font_size=10pt"
);
obj.format_cell(data: PROFILE_NAME
,overrides: "just=left font_face=Calibri color=black font_size=10pt");
obj.row_end();
obj.row_start();
obj.format_cell(data: "OBJECTIFS :"
,overrides: "font_face=Calibri just=left font_weight=bold color=blue font_size=10pt width=2.5 cm"
);
obj.format_cell(data: PROFILE_OBJECTIVES
,overrides: "font_face=Calibri just=left color=black font_size=10pt width=15 cm"
);
obj.row_end();
obj.table_end();
obj.layout_end();
run;
ODS PDF CLOSE;
%end;
%mend;
proc import
datafile="XXX\Exemple.xlsx"
out=RESULTAT
replace dbms=xlsx;
getnames=yes;
run;
%publi;
Thank you very much Tom!
I understood the code.
Best regards,
Marie
%nrstr works for me
data _null_;
%let PROFILE=%nrstr(ne devra représenter plus de 20 %du profil de gestion);
%put &PROFILE;
run;
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.