Taglib is a special extension to CSP, which allows one to define custom tags.
Currently CPPSERV CSP parser only supports compile-time taglibs. In other words, taglib is loaded while parsing the CSP document, and it affects generated C++ (as opposed to run-time taglibs, which would load at run-time, and would affect generated output. Currently CSP taglibs only support separate opening and closing tags.
Writing compile-time CSP taglib is pretty straight-forward. The basic steps are:
servlet::taglib::Generator
for each tag you want to implementdoStartTag
and doEndTag
functionsEXPORT_COMPILE_TIME_TAG
macro
with your prefix, tag name, and class name as arguments. This should be done for each tag.COMPILE_TIME_TAGLIB
macro with the prefix of your tags as an argument.
doStartTag
and doEndTag
functions have access to
body
, header
, and member
ostream pointers
for outputting generated code.
Note: pointers (specifically std::ostream*
). This means one has to
use something like *body<<"/*generated comment*/;
body
: the body of the generated servlet's service function.header
: the header portion of the generated servlet. It is meant for generating #include directives, and suchmember
: the place where member declarations in generated servlet can be placed.
Here is actual code:
#include <servlet/taglib/Generator.h>
#include <servlet/taglib/CompileTimeTaglib.h>
using namespace servlet;
using namespace taglib;
static inline void get_attr(const Generator::attribs_t& attribs,
const std::string& name, std::string& dest, const std::string& tag,
const std::string& default_val = std::string())
{
attribs_t::const_iterator it = attribs.find(name);
if(it!=attribs.end())
dest=it->second;
else if(!default_val.empty())
dest = default_val;
else
throw std::runtime_error(tag +" requires attribute "+name);
}
class ListIteratorTag: public Generator
{
public:
std::string m_list;
public:
ListIteratorTag(const std::string& name)
: Generator(name)
{}
virtual void doStartTag(const attribs_t& attribs);
virtual void doEndTag();
};
void ListIteratorTag::doStartTag(const Generator::attribs_t& attribs)
{
std::string var, type;
get_attr(attribs, "list", m_list, "mylib:foreach_list");
get_attr(attribs, "var", var, "mylib:foreach_list");
get_attr(attribs, "type", type, "mylib:foreach_list");
*body<<"for("<<type<<"::iterator "<<var<<"="<<m_list<<".begin();";
*body<<var<<"!="<<m_list<<".end(); "<<var<<"++) {\n\t";
}
void ListIteratorTag::doEndTag()
{
*body<<"}\n";
*body<<"/* end mylib:foreach_list: "<<m_list<<" */"<<std::endl;
}
EXPORT_COMPILE_TIME_TAG(mylib, foreach_list, ListIteratorTag)
COMPILE_TIME_TAGLIB(mylib)
Let's take the example apart, piece by piece.
The code above defines taglib with mylib
prefix,
and a single tag: foreach_list
. The tag uses three
attributes: list
, var
, and type
.
Resulting output code iterates over the list
, executing tag body, with
var
as iterator variable. For example:
When the page is executed, this should generate something like:
<%
std::list<int> testlist;
testlist.push_back(1);
testlist.push_back(10);
testlist.push_back(100);
%>
<UL>
<mylib:foreach_list list="testlist" var="val" type="std::list<int>">
<LI> Value: <%=*val%>
</mylib:foreach_list>
First we define class ListIteratorTag
, derived from Generator
.
Objects of this class will be instantiated every time <mylib:foreach_list>
is encountered,
and destroyed when </mylib:foreach_list>
is found.
std::string m_list;
function doStartTag
takes list of tag attributes which CSP parser found,
but doEndTag
does not. This means we have to save information used by doEndTag()
in member variables.
std::string var, type
Declare variables to hold attribute values.
Next three lines of doStartTag
function retrieve
list
, var
, and type
attributes,
throwing an exception, in case any of them is missing.
Next, simple for loop is generated, as well as opening brace. These are sent to the output stream representing the service function body.
doEndTag
function simply closes the brace and outputs
a comment, specifying that foreach_list for given list has been closed
here (for convenience of debugging, in case there is a syntax error
in the contained block).
EXPORT_COMPILE_TIME_TAG(mylib, foreach_list, ListIteratorTag)
COMPILE_TIME_TAGLIB(mylib)
These two lines register the tag and containing taglib.
Authoright © Total Knowledge: 1999-2013