To implement the DAS handler, start with the same boiler-plate code
used to create a main() for the DDS handler and replace the call
to the function that builds the DDS with one that builds a DAS. An
example of such a function from the Matlab server is shown below:
void
read_attributes(DAS &das_table, string filename)
{
AttrTable *attr_table = das_table.add_table("MAT_GLOBAL", new AttrTable);
MATFile *fp = matOpen(filename.c_str(), "r");
if (fp == NULL)
throw Error(string("Could not open the file: ") + filename.c_str());
// Read all the matrices in file
Matrix *mp;
while ((mp = matGetNextMatrix(fp)) != NULL) {
// String types are used as attributes
if(mxIsString(mp)) {
// get size
int X = mxGetN(mp);
int Y = mxGetM(mp);
char *str_rep = new char [X*Y+3];
// quote the string for parser
*str_rep = '"';
mxGetString(mp, str_rep+1, X*Y+1);
*(str_rep + X*Y + 1) = '"';
*(str_rep + X*Y + 2 )= '\0';
if (attr_table->append_attr(mxGetName(mp),
"String",str_rep) == 0) {
delete [] str_rep;
mxFreeMatrix(mp);
matClose(fp);
throw Error(string("Couldn't output attribute: ")
+ mxGetName(mp));
}
delete [] str_rep;
}
else {
das_table.add_table(mxGetName(mp), new AttrTable);
}
mxFreeMatrix(mp);
}
matClose(fp);
return true;
}
In this example the server creates a single attribute container called MAT_GLOBAL and loads all the data set attributes into it.
Most data set types (e.g., hdf) have both global attributes (those that apply to the entire data set) and attributes that only apply to a particular variable. Such data sets have both a global attribute container and separate attribute containers for each variable3. Matlab has only global attributes.
Here's what is going on inside this function:
First a new attribute table object is created and added to the DAS object. An attribute table (AttrTable) is similar to a structure in that it holds other things which may be attributes (typed name-value pairs) or other attribute tables. The DAS is a container for AttrTable objects. Take a look at the documentation for the AttrTable and DAS classes in the Programmer's Reference Guide.
AttrTable *attr_table = das_table.add_table("MAT_GLOBAL", new AttrTable);
Following the creation of a table for global attributes, the function handles the routine and API-dependent tasks of opening the data set and setting things up to iterate over its variables.
MATFile *fp = matOpen(filename.c_str(), "r");
if (fp == NULL)
throw Error(string("Could not open the file: ") + filename.c_str());
// Read all the matrices in file
Matrix *mp;
while ((mp = matGetNextMatrix(fp)) != NULL) {
Inside the while-loop that iterates over the data set's
variables, we test for string variables. The Matlab server assumes
that all string variables in a data set are actually global attributes
for the data set (and not `data' variables). If a string variable is
found, the code uses the variable's name and value as the attribute
name and value (code that handles the case where a variable is not a
string is explained further down).
Attributes are all string-valued in the DAP. That is, even though the
DAP supports the full range of scalar data types for attributes, the
values are stored as strings. The call to
AttrTable::append_attr adds the attribute tuple (Name, type and
value) to the AttrTable instance.
Note that if AttrTable::append_attr fails, it returns zero and
the code cleans up and throws an exception. I elided that from this
sniplet to focus the example.
// String types are used as attributes
if(mxIsString(mp)) {
// get size
int X = mxGetN(mp);
int Y = mxGetM(mp);
char *str_rep = new char [X*Y+3];
// quote the string for parser
*str_rep = '"';
mxGetString(mp,str_rep+1,X*Y+1);
*(str_rep + X*Y + 1) = '"';
*(str_rep + X*Y + 2 )= '\0';
if (attr_table->append_attr(mxGetName(mp), "String", str_rep) == 0) {
If the variable is not a string, then the Matlab server creates an empty attribute table for it. This is to conform to the DAP 2.0 specification which states that all variable must have an attribute table, even if it is empty.
else {
das_table.add_table(mxGetName(mp), new AttrTable);
}