BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
SASdevAnneMarie
Barite | Level 11

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;

SASdevAnneMarie
Barite | Level 11
Hello experts,
I added the code. 
I can't understand why %sysfunc(quote(%superq(&PROFILE_OBJECTIVES.))) doesn't works and I get the warning: WARNING: Apparent invocation of macro DU not resolved.

Thank you!
yabwon
Onyx | Level 15

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:

https://documentation.sas.com/?docsetId=mcrolref&docsetTarget=n0700fspmubii5n1vecutttwz93n.htm&docse...

 

Hope it helps

Bart

 

 

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



SASdevAnneMarie
Barite | Level 11
Thank you!
I see, but this is not working, I need the double quotation in my code: "&PROFILE_OBJECTIVES." 😞

Best regards,
Marie
yabwon
Onyx | Level 15

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:

DATA: <'string' | number | character-variable | numeric-variable>

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

 

 

 

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



SASdevAnneMarie
Barite | Level 11
Thank you very much!
Tom
Super User Tom
Super User

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
  ...

 

SASdevAnneMarie
Barite | Level 11

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;

 

 

Tom
Super User Tom
Super User

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.

Tom
Super User Tom
Super User

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;

 

SASdevAnneMarie
Barite | Level 11

Thank you very much Tom!

I understood the code.

 

Best regards,

Marie

ghosh
Barite | Level 11

%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: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

How to Concatenate Values

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 26 replies
  • 1692 views
  • 4 likes
  • 6 in conversation