aboutsummaryrefslogtreecommitdiff
path: root/vendor/voclient/libvotable/Notes
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/voclient/libvotable/Notes')
-rw-r--r--vendor/voclient/libvotable/Notes624
1 files changed, 624 insertions, 0 deletions
diff --git a/vendor/voclient/libvotable/Notes b/vendor/voclient/libvotable/Notes
new file mode 100644
index 00000000..b288b873
--- /dev/null
+++ b/vendor/voclient/libvotable/Notes
@@ -0,0 +1,624 @@
+
+VOTPARSE -- VOTable parser API. This interface allows a VOTable to read
+read or created from a number of calling languages. XML parsing is done
+using a SAX parser on input, when creating new VOTables the API is used
+to populate the VOTable structure before writing the final output.
+
+We attempt to implement all aspects of the VOTable v1.2 specification and
+remain compatible with earlier versions to the extent possible.
+
+
+
+ Public Interface:
+ -----------------
+
+ vot = vot_openVOTABLE (str|fname)
+ vot_closeVOTABLE (vot)
+
+ res = vot_getRESOURCE (vot|res)
+ tab = vot_getTABLE (res)
+ field = vot_getFIELD (tab)
+
+ data = vot_getDATA (tab)
+
+ tdata = vot_getTABLEDATA (data) // data elements
+ tr = vot_getTR (tdata)
+ td = vot_getTD (tr)
+ bin = vot_getBINARY (data)
+ fits = vot_getFITS (data)
+
+ group = vot_getGROUP (vot|res|tab|group)
+ fldref = vot_getFIELDRef (group)
+ parref = vot_getPARAMRef (group)
+
+
+ desc = vot_getDESCRIPTION (handle)
+ param = vot_getPARAM (handle)
+ info = vot_getINFO (handle)
+ stream = vot_getSTREAM (bin|fits)
+
+ val = vot_getVALUES (field|param|info)
+ min = vot_getMIN (val)
+ max = vot_getMAX (val)
+ opt = vot_getOPTION (val)
+
+ link = vot_getLINK (res|info|param|field|table)
+
+ sys = vot_getCOOSYS (vot) // backwards compat.
+
+
+ handle = vot_newNode (parent, type)
+ vot_attachNode (parent, handle)
+ vot_deleteNode (handle)
+
+ Output Routines:
+
+ vot_writeVOTable (vot, fd)
+ vot_writeHTML (vot, fd)
+ vot_writeDelimitedTable (vot, fd, delim) w
+
+
+ Convenience Functions:
+
+ str = vot_getTableCell (tdata, row, col)
+
+ n = vot_getNRows (tdata)
+ n = vot_getNCols (tdata)
+
+ type = vot_getDATAType (data)
+
+ str = vot_getAttr (handle, attr)
+ stat = vot_setAttr (handle, attr, value)
+
+ str = vot_getValue (handle)
+ str = vot_setValue (handle, value)
+
+ len = vot_getLength (handle)
+ len = vot_getNumberOf (handle, type)
+
+ handle = vot_findByAttr (parent, type, attr, value)
+ handle[] = vot_findInGroup (group, TY_FIELD|TY_PARAM)
+
+
+ Low-level Interface (Private?):
+
+ handle = vot_getNext (handle)
+ handle = vot_getSibling (handle)
+ handle = vot_getChild (handle)
+ handle = vot_getChildOfType (handle, type)
+ handle = vot_getParent (handle)
+
+ type = vot_valueOf (handle)
+
+
+------------------------------------------------------------------------------
+
+Data Structures
+---------------
+
+
+#define TY_VOTABLE 1
+#define TY_RESOURCE 2
+#define TY_FIELD 3
+#define TY_PARAM 4
+#define TY_INFO 5
+#define TY_ROW 6
+#define TY_DATA 7
+#define TY_VALUES 8
+#define TY_STREAM 9
+#define TY_LINK 10
+#define TY_FIELDREF 11
+#define TY_PARAMREF 12
+#define TY_OPTION 13
+#define TY_MIN 14
+#define TY_MAX 15
+#define TY_FITS 16
+#define TY_TABLE 17
+#define TY_GROUP 18
+#define TY_COOSYS 19
+
+
+#define MAX_ATTRS 11
+#define SZ_ATTR_NAME 16
+#define SZ_ATTR_VALUE 64
+
+
+typedef unsigned int handle_t;
+
+
+typedef struct {
+ char name[SZ_ATTR_NAME]; /* attribute name */
+ char value[SZ_ATTR_VALUE]; /* attribute value */
+
+} Attr, *AttrP;
+
+
+typedef struct {
+ char type; /* node type */
+
+ void *next; /* sibling node */
+ void *child; /* child nodes */
+ void *child_last; /* last child node */
+ void *parent; /* parent node */
+
+ char *data; /* value string */
+
+ Attr attr[MAX_ATTRS]; /* attribute array */
+ int nattrs; /* number of attributes */
+
+} Node, *NodeP;
+
+
+ - Need to keep track of last child so we can easily append new tags
+ - The 'data' string is any text in the xml element, e.g. given
+
+ <TD>yada yada yada</TD>
+
+ the 'data' string is then 'yada yada yada'
+ - structs should be calloc'd to initialize to NULL
+
+
+
+------------------------------------------------------------------------------
+
+Notes:
+------
+
+ - The 'handle' is an opaque reference to the node that is meant to
+ be language-neutral. In reality it is just the pointer to the Node
+ struct cast as an integer. Note that on 64-bit platforms, bindings
+ will require the handle to be typed as a 'long'value.
+
+ - The vot_openVOTable() is used both for reading and writing VOTables.
+ The read, the argument may a string which is a filename to be read or
+ a literal string assumed to be the VOTable document itself. If
+ passed a NULL pointer, a new document structure will be created and
+ we assume we'll write it out later.
+
+ - The various vot_get<Tag>() functions in reality only return the single
+ handle of the specified type, or a NULL if not found. This node
+ is required to be a child of the argument (parent) node.
+
+ vot_getFIELD (handle_t parent)
+ {
+ Node *ip = (handle_t) NULL;:
+ Node *p = (Node *) parent;
+ Node *c = p->child;
+ int ptype = p->type;
+
+ if (ptype != TY_TABLE) // check for valid parent
+ fprintf (stderr, "Invalid node for FIELDs\n");
+
+ for (ip=c; ip; ip = ip->next)
+ if (ip->type == TY_FIELD)
+ break;
+
+ return ((handle_t) ip);
+ }
+
+
+ - A call to vot_getNext() returns the next sibling of the same type as
+ the arg. In contrast, vot_getSibling() returns the next sibling node
+ regardless of type.
+
+ vot_getNext (handle_t tag)
+ {
+ Node *ip:
+ Node *np = (Node *) tag;
+ int type = p->type;
+
+ for (ip=np->next; ip; ip = ip->next)
+ if (ip->type == np->type)
+ return ((handle_t) ip);
+
+ return ((handle_t) NULL);
+ }
+
+ vot_getSibling (handle_t tag)
+ {
+ Node *np = (Node *) tag;
+
+ return ((handle_t) np->next);
+ }
+
+ - vot_newNode() creates an empty node structure, other calls are used
+ to populate the attributes, values, or child nodes. OTOH, methods
+ like vot_attachNode() / vot_deleteNode() use handles that can refer
+ to sub-trees. This makes it easy to refer to e.g. an entire RESOURCE
+ and then attach it to a new document or delete entirely. The
+ methods that care of adusting the child/next pointers.
+
+ vot_newNode (handle_t parent, int type)
+ {
+ Node *np = (Node *) calloc (1, sizeof (Node));
+ np->type = type;
+ return ((handle_t) np);;
+ }
+
+ vot_attachNode (handle_t parent, handle_t node)
+ {
+ Node *p = (Node *) parent,
+ *n = (Node *) node,
+ *last = p->child_last;
+
+ if (p->child)
+ last->next = n; // append existing children
+ else
+ p->child = n; // make an only child
+ p->child_last = n // update parent
+ }
+
+ vot_deleteNode (handle_t node)
+ {
+ Node *n = (Node *) node,
+ *p = n->parent,
+ *last = p->child_last,
+ *prev = (Node *) NULL;
+
+ if (p->child == n) { // node is first child
+ p->child = n->next;
+
+ } else {
+ // Find the previous sibling node
+ for (prev=p->child; prev->next != n; prev=prev->next)
+ ;
+
+ prev->next = n->next;
+ if (p->child_last == n) //update parent
+ p->child_last = prev;
+ }
+
+ vot_freeNode (n); // free the node sub-tree
+ }
+
+
+ The vot_freeNode() method would need to walk the tree in a
+ depth-first manner to free the Node strucutres. The vot_closeVOTable()
+ then is simply a call to this on the root node
+
+
+
+ - Fortran bindings should use the subroutine model to avoid having to
+ declare numerous functions. E.g.
+
+ The C method
+
+ field = vot_getFIELD (tab)
+
+ is used in Fortran as
+
+ call getFIELD (tab, field)
+
+ Implementation of the wrapper is then simply
+
+ void getFIELD (handle_t parent, handle_t *field)
+ {
+ *field = vot_getFIELD (parent);
+ }
+
+
+ Methods that pass strings need to take into account the hidden length
+ parameter used in fortran. E.g.
+
+ The C method
+ valueStr = vot_getAttr (handle, attr)
+
+ is used in Fortran as
+
+ call getAttr (handle, attr, valueStr)
+
+ However, the implementation is
+
+ void getAttr (handle_t parent, char *a, char *v, int alen, int vlen)
+ {
+ *v = vot_getAttr (parent, a);
+ }
+
+ The 'alen' and 'vlen' args are added by the Fortran compiler to pass
+ in the length of the string. In some cases we may also want to pass
+ in the max length of a result string so we don't overflow a buffer,
+ or else return the length of the string we found. Since Fortran is
+ call-by-address in either of these cases the length becomes a pointer
+ declaration.
+
+
+
+------------------------------------------------------------------------------
+
+
+PseudoCode:
+-----------
+
+
+1) Read a VOTable, processing each RESOURCE in the file. Note we don't
+ handle *nested* RESOURCEs here.
+
+
+ vot = vot_openVOTable (fname)
+
+ // loop over RESOURCES
+ res = vot_getRESOURCE (vot, i);
+ printf ("Table has toplevel %d RESOURCE elements\n",
+ vot_getLength (res));
+
+ while ( res ) {
+
+ tab = vot_getTABLE (res)
+
+ // Print column info
+ for (field=vot_getFIELD(tab); field; field=vot_getNext(field)) {
+ strcpy (col[i].name, vot_getAttr (field, "name")
+ strcpy (col[i].ucd, vot_getAttr (field, "ucd")
+ }
+
+ // Get the data element
+ data = vot_getDATA (tab)
+
+ switch (vot_getDataType (data))
+ case TY_TABLEDATA:
+ // Get data stored as a TABLEDATA xml block
+ tdata = vot_getTABLEDATA (data)
+
+ if (use_direct) {
+ // Get the table data cells by direct index
+ tr = vot_getTR(tdata)
+ nrows = vot_getLength (tr)
+ ncols = vot_getLength (vot_getTD(tr))
+ for (l=0; l < nrows ; l++) {
+ for (m=0; m < ncols; m++) {
+ str = vot_getTableCell (tdata, l, m)
+
+ } else {
+ // Get the table data cells by looping over rows/cols
+ for (tr=vot_getTR (tdata); tr; tr=vot_getNext(tr))
+ for (td=vot_getTD(tr); td; td=vot_getNext(td))
+ str = vot_getValue (td);
+ }
+ break
+
+ case TY_BINARY:
+ // Get data stored as inline binary. If the encoding of
+ // the stream is base64 read the sequence of bytes and decode.
+ bin = vot_getBINARY (data)
+ stream = vot_getSTREAM (bin)
+ if (strcmp ("base64", vot_getAttr(stream, "encoding") == 0)
+ str = vot_getValue (stream)
+ break
+
+ case TY_FITS:
+ // Read FITS data. Assumes a particular extension of an
+ // MEF is available for download at the given href.
+ fits = vot_getFITS (data)
+ extnum = vot_getAttr (fits, "extnum") // get extension no.
+
+ stream = vot_getSTREAM (fits)
+ href = vot_getAttr (stream, "href")
+
+ ....download the FITS file ....
+
+ break
+ default:
+ error (0, "Invalid table DATA type.")
+ }
+
+ res = vot_getNext(res) // get next resource
+ }
+
+ vot_closeVOTable (vot)
+
+
+
+
+2) Print all the PARAM elements in a table with a single RESOURCE
+
+ a) Use the low-level interface dealing with document structure
+
+ res = vot_getRESOURCE (vot)
+ for (p = vot_getChild (res); p; p = vot_getSibling (p)) {
+ if (vot_typeOf (p) == TY_PARAM)
+ printf ("PARAM name=%s value=%s\n",
+ vot_getAttr(p, "name"), vot_getAttr(p, "value"))
+ }
+
+ b) Use the common hi-level interface
+
+ res = vot_getRESOURCE (vot)
+ for (p = vot_getPARAM (res); p; p = vot_getNext (p)) {
+ printf ("PARAM name=%s value=%s\n",
+ vot_getAttr(p, "name"), vot_getAttr(p, "value"))
+ }
+
+
+
+
+3) Check a VOTable to see if it is an error return
+
+ a) SCS-only (Preferred) Method - INFO as a child of VOTABLE
+
+ vot = vot_openVOTable (fname)
+ if ((info = vot_getINFO (vot)) {
+ if (strcsecmp (vot_getAttr (info, "name"), "error") == 0)
+ return ((errMsg = vot_getAttr (info, "value")))
+ } else
+ return ("file is okay")
+
+
+ b) Alternate Method - PARAM as a child of RESOURCE "allowed" for SCS,
+ required for other DAL services. For SCS, the name/id are different,
+ later DAL services use 'QUERY_STATUS'.
+
+ vot = vot_openVOTable (fname)
+ res = vot_getRESOURCE (vot)
+ param = vot_getPARAM (res)
+ info = vot_getINFO (res)
+
+ if (strcasecmp(vot_getAttr (param, "name"), "error") == 0) {
+ // SCS alternate method where PARAM defines value the error string
+ return (vot_getAttr (param, "value"))
+
+ } else if (strcasecmp(vot_getAttr(info,"name"),"QUERY_STATUS") == 0) {
+ // All-other DAL methods where and INFO of the RESOURCE defines
+ // a QUERY_STATUS of the result.
+ if ( ((val = vot_getAttr (info, "value")), "OK") == 0)
+ return (NULL); // no error
+ else
+ return (vot_getValue (info)) // return error message
+ }
+
+
+ NOTES: We should make this an interface convenience. A real
+ error will be a minimal VOTable error return we can parse, but
+ DAL2 services like TAP may experience overflow where we don't see
+ an error result until a max-records/timeout is reached and the
+ error INFO is at the end of the output. In this last case the
+ error INFO isn't seen until after table data. To be real, we
+ need to then search all INFO children of the RESOURCE rather than
+ just the first one shown in the above.
+
+
+
+4) Create a new VOTable from computed values
+
+ vot = vot_openVOTable (NULL) // initialize
+
+ res = vot_newNode (vot, TY_RESOURCE) // create empty resource
+ vot_setAttr (res, "id", "newTable") // set table name
+
+
+ desc = vot_newNode (vot, TY_DESCRIPTION) // set description
+ vot_setValue (desc, "This is a test description")
+
+ tab = vot_newNode (res, TY_TABLE) // create a TABLE
+ for (i=0; i < 10; i++) {
+ f = vot_newNode (tab, TY_FIELD)
+ sprintf (colname, "col%d", i)
+ vot_setAttr (f, "name", colname)
+ vot_setAttr (f, "id", colname)
+ : :
+ }
+
+ data = vot_newNode (tab, TY_DATA) // create a DATA
+ tdata = vot_newNode (data, TY_TABLEDATA) // create a TABLEDATA
+
+ for (i=0; i < nrows; i++) {
+ tr = vot_newNode (tdata, TY_TR) // create a row
+ for (j=0; j < ncols; j++) {
+ td = vot_newNode (tr, TY_TD) // create a col
+ vot_setValue (td, (char *)data[i,j])
+ }
+ }
+
+ info = vot_newNode (tab, TY_INFO) // create a DATA
+ vot_setAttr (info, "id", "STATUS")
+ vot_setAttr (info, "value", "OK")
+
+
+ vot_writeVOTable (vot, stdout) // write it out
+
+
+
+4-A) Create a new VOTable from computed values (Alternate Method)
+
+ vot = vot_openVOTable (NULL) // initialize
+
+ res = vot_newRESOURCE (vot) // create empty resource
+ vot_setAttr (res, "id", "newTable") // set table name
+
+ // set description
+ desc = vot_newDESCRIPTION (vot, "This is a test description")
+
+ tab = vot_newTABLE (res) // create a TABLE
+ for (i=0; i < 10; i++) {
+ f = vot_newFIELD (tab)
+ sprintf (colname, "col%d", i)
+ vot_setAttr (f, "name", colname)
+ vot_setAttr (f, "id", colname)
+ : :
+ }
+
+ data = vot_newDATA (tab) // create a DATA
+ tdata = vot_newTABLEDATA (data) // create a TABLEDATA
+
+ for (i=0; i < nrows; i++) {
+ tr = vot_newTR (tdata) // create a row
+ for (j=0; j < ncols; j++) {
+ td = vot_newTD (tr) // create a col
+ vot_setValue (td, (char *)data[i,j])
+ }
+ }
+
+ info = vot_newINFO (tab) // create a DATA
+ vot_setAttr (info, "id", "STATUS")
+ vot_setAttr (info, "value", "OK")
+
+
+ vot_writeVOTable (vot, stdout) // write it out
+
+
+5) Concatenate the RESOURCEs from two input table to a new output table
+
+ vot1 = vot_openVOTABLE ("file1.xml") // open input tables
+ vot2 = vot_openVOTABLE ("file2.xml")
+
+ res1 = vot_getRESOURCE (vot1) // get resources
+ res2 = vot_getRESOURCE (vot2)
+
+ vot3 = vot_openVOTABLE (NULL) // open output table
+
+ vot_attachNode (vot3, vot1) // add resources
+ vot_attachNode (vot3, vot2)
+
+ vot_writeVOTable (vot2, stdout) // write it out
+
+ vot_closeVOTABLE (vot1) // clean up
+ vot_closeVOTABLE (vot2)
+ vot_closeVOTABLE (vot3)
+
+
+6) Extract all the values in the columns specified by a GROUP
+
+ vot = vot_openVOTable (fname)
+ res = vot_getRESOURCE (vot)
+ tab = vot_getTABLE (res)
+
+ // Look for the GROUP by name
+ for (group=vot_getGROUP(res); group; group=vot_getNext(group))
+ if (strcasecmp (vot_getAttr(group,"name"), "CoolStuff") == 0)
+ break;
+
+ // Gather the column numbers for the FIELDs in the GROUP
+ for (fref=vot_getFIELDRef(group); fref; fref=vot_getNext(fref)) {
+ // Get the field references
+ ref = vot_getAttr (fref, "ref")
+
+ // Find the FIELD with the referenced ID attribute,
+ field = vot_findByAttr (tab, TY_FIELD, "ID", ref)
+
+ // Convert to a column number to extract
+ fp = vot_getField (tab) // start FIELD
+ colnum = -1
+ while (fp && fp != field) {
+ colnum++; // 0-indexed list
+ fp = vot_getNext (fp)
+ }
+
+ cols[numInGroup++] = colnum
+ }
+
+ // Print out the data in selected columns
+ data = vot_getDATA (tab)
+ tdata = vot_getTABLEDATA (data)
+ tr = vot_getTR(tdata)
+ nrows = vot_getLength (tr)
+
+ for (i=0; i < nrows ; i++) {
+ for (j=0; j < numInGroup; j++)
+ printf ("%s ", vot_getTableCell (tdata, i, cols[j])
+ printf ("\n")
+ }
+
+
+
+
+
+