/* prepend a template store, work.myTmp to ods path */
ods path (prepend) work.myTmp(update);
/* create a tagset, hfTab - html table with "filtering" */
proc template;
define tagset tagsets.hfTab;
/* ods events */
define event option;
set $name upcase(name);
set $options[$name] value; /* collect options specified */
end;
define event table_body;
start:
trigger openTable;
trigger doHeaders;
finish:
trigger closeTable;
end;
define event colspec_entry;
break /if cmp(name, 'obs'); /* ignore the obs column */
set $names[] name; /* collect column names */
end;
define event row;
start: /* some init for each row */
break /if ^$inTable;
unset $trClasses;
unset $tds;
finish:
break /if ^$inTable;
unset $class; /* open tr with classes, if any */
iterate $trClasses;
do /while _value_;
set $class catx(' ', $class, _value_);
next $trClasses;
done;
put "<tr";
put " class='" $class "'" /if ^missing($class);
put ">";
iterate $tds; /* output cells in the row */
do /while _value_;
put _value_;
next $tds;
done;
putl "</tr>"; /* close tr tag */
end;
define event data;
set $name upcase(name);
/* if column name matches a column filter then add a class attribute */
do /if $cfClasses[$name];
set $tds[] "<td class='" $cfClasses[$name] "'>" value "</td>";
else;
set $tds[] "<td>" value "</td>";
done;
/* if the cell matches a row filter then collect the class name */
set $trClasses[] $rfClasses[$name] /if cmp($rfValues[$name], value);
end;
/* user events */
define event openTable;
put "<table";
put " width=" quote($options["WIDTH"]) /if $options["WIDTH"];
putl ">";
trigger parseRowFilters /if $options["ROWFILTERS"];
trigger parseColFilters /if $options["COLFILTERS"];
set $inTable "True";
end;
define event doHeaders;
put "<tr>";
iterate $names;
do /while _value_;
set $name upcase(_value_);
do /if $cfClasses[$name];
put "<th class='" $cfClasses[$name] "'>" _value_ "</th>";
else;
put "<th>" _value_ "</th>";
done;
next $names;
done;
putl "</tr>";
end;
define event closeTable;
putl "</table>";
unset $options;
unset $inTable;
unset $names;
end;
/* for parsing filter options */
define event parseRowFilters;
set $str $options["ROWFILTERS"];
trigger getList;
iterate $list;
do /while _value_;
set $var scan(_value_, 1);
set $var upcase($var);
set $rfValues[$var] scan(_value_, 2);
set $rfClasses[$var] scan(_value_, 3);
next $list;
done;
unset $list;
end;
define event parseColFilters;
set $str $options["COLFILTERS"];
trigger getList;
iterate $list;
do /while _value_;
set $var scan(_value_, 1);
set $var upcase($var);
set $cfClasses[$var] scan(_value_, 2);
next $list;
done;
unset $list;
end;
/* utility */
define event getList;
/* given $str of a delimited list, returns a list, $list[] */
break /if missing($str);
set $dlm ",";
eval $i 1;
set $item scan($str, $i, $dlm);
do /while ^missing($item);
set $list[] strip($item);
eval $i $i + 1;
set $item scan($str, $i, $dlm);
done;
end;
/* quote those (in)famous five */
map = %nrstr("<>&'""");
mapsub = %nrstr("/</>/&/'/"/");
end;
run;
/* usage */
ods tagsets.hfTab file=_webout
options(width='100%' colfilters='weight weight'
rowfilters='sex F girl, name Thomas thomas, age 12 twelve');
proc print data=sashelp.class;
where age <= 12;
run;
ods tagsets.hfTab close;
/* _webout
<table width="100%">
<tr><th>Name</th><th>Sex</th><th>Age</th><th>Height</th><th class='weight'>Weight</th></tr>
<tr class='twelve'><td>James</td><td>M</td><td>12</td><td>57.3</td><td class='weight'> 83.0</td></tr>
<tr class='girl twelve'><td>Jane</td><td>F</td><td>12</td><td>59.8</td><td class='weight'> 84.5</td></tr>
<tr class='twelve'><td>John</td><td>M</td><td>12</td><td>59.0</td><td class='weight'> 99.5</td></tr>
<tr class='girl'><td>Joyce</td><td>F</td><td>11</td><td>51.3</td><td class='weight'> 50.5</td></tr>
<tr class='girl twelve'><td>Louise</td><td>F</td><td>12</td><td>56.3</td><td class='weight'> 77.0</td></tr>
<tr class='twelve'><td>Robert</td><td>M</td><td>12</td><td>64.8</td><td class='weight'>128.0</td></tr>
<tr class='thomas'><td>Thomas</td><td>M</td><td>11</td><td>57.5</td><td class='weight'> 85.0</td></tr>
</table>
*/
/* clean up */
ods path reset;
Available on demand!
Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.
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.