I don't think any pre-existing ODS destination would give a clean HTML snippet that OP wants to generate and to flush out into _webout.
But you can do this with a very simple (in fact, some would say, elementary) custom tagset that listens to only a few events.
As it is, a variable can take a maximum of one row and one column (equality) filters. Thus, there can be as many row/column filters as the number of variables. (Can you see why?)
It is really easy to modify this tagset so that it can take multiple row/column filters for each var. This is left as an exercise for those who are interested. 🙂
It may be a bit more involved to generalize this so that the "filter" accommodates non-equality as well.
For those who are trying, here is a hint:
It would involve users writing the filters using a marker (or a place holder) for the variable in the expression,
so that the tagset can replace the marker with actual value of the cell and evaluate the expression.
A natural marker may be the variable name itself.
This is not really that involved at all.
P.S. Please don't be alarmed by the red-colored keywords that look like errors ("undefined keywords") -- they are not.
Come on, the editor dev team!
This has been available all along ...
/* 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;
Message edited: "Filtering" implemented. by chang_y_chung@hotmail.com on 2011-01-12
... View more