BookmarkSubscribeRSS Feed
ChrisNZ
Tourmaline | Level 20
After fluffing around,I managed to get this code working (in 9.1.3) to add dummy anchors to html pages.

%macro IncrementIDX;
proc template;
define table IncrementIDX;
column a;
define a;
generic=on;
end;
end;
run;
title; footnote;
data _null_;
a=1;
file print ods=(template='IncrementIDX');
put _ods_;
run;
%mend;

I am unsure why it works though. generic=on seems to be the key. Can someone explain?
9 REPLIES 9
Cynthia_sas
SAS Super FREQ
Hi:
I'm not sure what you mean by adding "dummy anchors" to ODS HTML output. For example, I do NOT need GENERIC=ON to get an IDX tag built for this TABLE template and DATA step:
[pre]
ods path work.temp(update) sasuser.templat(update) sashelp.tmplmst(read);
proc template;
define table IncrementIDX;
column a;
define a;
header='Without Generic for A';
end;
end;
run;

title; footnote;
ods listing close;
ods html file='c:\temp\testIDX.html' style=sasweb;
data _null_;
a=1;
file print ods=(template='IncrementIDX');
put _ods_;
run;
ods html close;
[/pre]

The generated HTML is:
[pre]
<div class="branch">
<a name="IDX"></a>
<div>
<div align="center">
<table class="Table" cellspacing="1" cellpadding="7" rules="none" frame="box" summary="Procedure Datastep: FilePrint1">
<colgroup>
<col>
</colgroup>
<thead>
<tr>
<th class="r b Header" scope="col">Without Generic for A</th>
</tr>
</thead>
<tbody>
<tr>
<td class="r Data">1</td>
</tr>
</tbody>
</table>
</div>
</div>
<br>
</div>
</body>
</html>
[/pre]

Depending on where/how/why you want to insert an "extra" named section, you might be able to insert your extra named anchors by just using ODS TEXT= (if you were in SAS 9.1.3, you'd need to use ODS HTML TEXT=). There's an example below. The titles and footnotes contain links to the named anchors that were inserted in the ODS TEXT= statements.

cynthia
[pre]
title; footnote;
ods html file='c:\temp\insertIDX.html' style=sasweb;

ods text='<div class="branch"><a name="MYIDX">&nbsp;</a></div>';

proc print data=sashelp.class(obs=2);
title link='#MYIDX1' 'Go to Shoes';
title2 link='#MYIDX2' 'Go to Furniture';
run;

ods text='<div class="branch"><a name="MYIDX1">&nbsp;</a></div>';

proc print data=sashelp.shoes(obs=20);
title 'Shoe Report';
title2 link='#MYIDX' 'Go Back to Top';
title3 link='#MYIDX2' 'Go to Furniture';
run;

ods text='<div class="branch"><a name="MYIDX2">&nbsp;</a></div>';

proc print data=sashelp.prdsale(obs=20);
title 'Furniture Report';
footnote link='#MYIDX' 'Go Back To Top';
footnote2 link='#MYIDX1' 'Go to Shoes';
footnote3 link='#MYIDX2' 'Go to Furniture';
run;
ods html close;
title; footnote;
[/pre]
ChrisNZ
Tourmaline | Level 20
Hi Cynthia,


My code just inserts
[pre]
<div class="branch">
<a name="IDX10">
<div>
</div>
<br>
</div>
[/pre]
in the html page. Your code adds a table.

I need this dummy anchor because when I generate outputs, there is no suitable data at times for a group, but the menu pointing to the groups must be kept in sync.
So I write out a message that uses one IDX anchor, and add "dummy" anchors to pad to the next group.
Cynthia_sas
SAS Super FREQ
Hi:
I'm confused...my PROC PRINTS are each generating the "original" IDX anchors, but my ODS TEXT is ONLY generating this:
[pre]
ods text='<div class="branch"><a name="MYIDX1">&nbsp;</a></div>';
[/pre]

There is only an &nbsp; inside the <A> tag...no <TABLE> tag. If you took out the PROC PRINTs, you would see only the results of my ODS TEXT= statements.

cynthia
ChrisNZ
Tourmaline | Level 20
Indeed you are right, Cynthia.

Your "ods text" ("ods html text" for me in 9.1) line inserts the HTML line you describe. Sorry about my confused reply.

The "ods text" line does not however stealthily (as in: nothing is visible on the HTML page) increment the sas counter for IDX anchor tags.

My code does that (there might be a simpler way to do it), but I don't understand how it works.
Cynthia_sas
SAS Super FREQ
Hi:
Think of the icons that appear in the SAS Results Window -- every output that would normally go to ODS is a branch and every branch gets an IDX. This is represented in the Results Window as the main folder or node with the + sign next to it. That folder is a "branch". So when you use FILE PRINT ODS, your output will generate a branch and the IDX will increment.

If I submit the following program:
[pre]
ods html file='c:\temp\look_at_IDX.html' style=sasweb;

data _null_;
a = ' ';
file Print ods;
put _ods_;
run;

proc print data=sashelp.class(obs=2);
run;

data _null_;
set sashelp.class(obs=3);
file Print ods;
put _ods_;
run;

ods html close;
[/pre]

Then I will get 3 "branches", one for each step-- and the resulting named anchors will be:
[pre]
<a name="IDX">
<a name="IDX1">
<a name="IDX2">
[/pre]
...each one within its own "branch" and <div> tag.

I didn't bother with a table template for my DATA _NULL_ because all I wanted to do was show that each "branch" got an IDX -- whether you used a TABLE template or now.

However, I can "force" the IDX to be a different number. I still don't know whether this is what you want to do. If you do this (using the ANCHOR= option), then the next anchor tag generated will start from that number. For example:
[pre]

data _null_;
a = ' ';
file Print ods;
put _ods_;
run;

proc print data=sashelp.class(obs=2);
run;

data _null_;
set sashelp.class(obs=3);
file Print ods;
put _ods_;
run;

ods html anchor='IDX15';
run;

proc print data=sashelp.shoes(obs=3);
run;

proc freq data=sashelp.shoes;
tables region;
run;

ods html close;
[/pre]

...will generate these named anchors in the file:
[pre]
<a name="IDX">
<a name="IDX1">
<a name="IDX2">
<a name="IDX15">
<a name="IDX16">
[/pre]

I'm still not sure I understand exactly why you need to increment anchor tags, but perhaps ANCHOR= will do what you want.

cynthia
ChrisNZ
Tourmaline | Level 20
Here is the background, Cynthia:

Each page has a menu with an entry per group and some other explanations at the top. I don't use frames, pages are part of a larger web site that handles the overall navigation.

On a page, say I create 3 graphs for each group. I know for example the menu will be IDX, the explanations IDX1, and each group will be IDX2, IDX5, IDX8, etc. These anchors are what the menu uses.

Now sometimes, graphs cannot be created. So I print a message (which uses one IDX, say IDX5) and I need 2 more increments so the next group, (at IDX8) will be navigated to properly from the menu.

I need these dummy anchors because when I generate outputs, if there is no suitable data for a group, the menu pointing to the groups must be kept in sync. So I add "dummy" anchors to pad to the next group.

Does this make sense?

The anchor increment works fine, it is just that I don't know why it does .
Cynthia_sas
SAS Super FREQ
Hi:
You said:
The anchor increment works fine, it is just that I don't know why it does .

And the reason it works only has a little to do with GENERIC=ON -- I can make the same thing happen by using PRINT=NO.

Your DATA _NULL_ step makes a high-level node -- an object (folder icon) in the Result Window and a "branch" in the HTML file. It doesn't matter whether you use a table template or not (as my previous program illustrated. Any output that gets routed to ODS, whether with a DATA _NULL_ or a PROC step generally gets a named anchor in the ODS HTML file. If I make a TABLE template but with PRINT=NO instead of GENERIC=ON -- even though my DATA _NULL_ doesn't generate any output in the HTML file, I will still get a named anchor in the HTML file from this code:
[pre]
proc template;
define table IncrementIDX;
column a;
define a;
print=no;
end;
end;
run;


title; footnote;
ods html file='c:\temp\whatIDX.html' style=sasweb;
proc print data=sashelp.class(obs=2);
run;

data _null_;
a=1;
file print ods=(template='IncrementIDX');
put _ods_;
run;

proc print data=sashelp.class(obs=2);
run;
ods html close;
[/pre]

And the IDX/named anchors in the ODS HTML file will be:
[pre]
<a name="IDX"> <---from 1st proc print
<a name="IDX1"> <---from DATA _NULL_
<a name="IDX2"> <---from 2nd proc print
[/pre]

When you use GENERIC=ON in the TABLE template, you are telling the TABLE template that you will be sending a variable from your dataset to the column. And normally, you do this because let's say you have a column in the template called "GENCOL" and you want to send that single column definition multiple numeric variables from your dataset -- in order to "reuse" the column definition. You would use the GENERIC column in this way:
[pre]
proc template;
define table Xtable;
column Region gencol;

define Region;
header='Region';
just=c;
style=RowHeader;
format=$15.;
end;
define gencol;
header=_label_;
format=comma14.2;
generic;
end;
end;
run;

data _null_;
set sashelp.shoes(obs=3);
label sales='Sales'
inventory='Inventory'
returns='Returns';
file print
ods=(template='Xtable'
columns=(Region
gencol=sales(generic=on)
gencol=inventory(generic=on)
gencol=returns(generic=on)));
put _ods_;
run;
[/pre]

Note how I am sending GENCOL the SALES variable first, then the INVENTORY variable and then the RETURNS variable. But GENERIC is like a handshake, if you have GENERIC (or GENERIC=ON) in the TABLE template, you are expected to have GENERIC in the COLUMNS= specification. Since you invoke the TABLE template without completing the handshake, you are essentially creating an "empty" output object -- which is essentially doing the same as when I had PRINT=NO In my template.

If I tried to use/create GENCOL in a DATA _NULL_ like this:
[pre]
data _null_;
set sashelp.shoes(obs=3);
label sales='Sales'
inventory='Inventory'
returns='Returns';
gencol=sales-inventory;
file print
ods=(template='Xtable'
columns=(Region
gencol ));
put _ods_;
run;
[/pre]

Then I would only see REGION in the output because I did not send a value for GENCOL in the table template in the proper way.

cynthia
ChrisNZ
Tourmaline | Level 20
Thank you for your very detailed and clear explanations Cynthia.

I might even be getting my head around proc template... 🙂

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

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
  • 9 replies
  • 1378 views
  • 0 likes
  • 2 in conversation