mxml/www/docfiles/CustomDataTypes.html
Michael R Sweet 61ba926ecc Prep for 2.1.
2004-11-13 18:26:38 +00:00

168 lines
5.5 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<TITLE>Mini-XML Programmers Manual, Version 2.1</TITLE>
<META NAME="author" CONTENT="Michael Sweet">
<META NAME="copyright" CONTENT="Copyright 2003-2004">
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-iso-8859-1">
<LINK REL="Start" HREF="index.html">
<LINK REL="Contents" HREF="toc.html">
<LINK REL="Prev" HREF="SaveCallbacks.html">
<LINK REL="Next" HREF="ChangingNodeValues.html">
<STYLE TYPE="text/css"><!--
BODY { font-family: serif }
H1 { font-family: sans-serif }
H2 { font-family: sans-serif }
H3 { font-family: sans-serif }
H4 { font-family: sans-serif }
H5 { font-family: sans-serif }
H6 { font-family: sans-serif }
SUB { font-size: smaller }
SUP { font-size: smaller }
PRE { font-family: monospace }
--></STYLE>
</HEAD>
<BODY>
<A HREF="toc.html">Contents</A>
<A HREF="SaveCallbacks.html">Previous</A>
<A HREF="ChangingNodeValues.html">Next</A>
<HR NOSHADE>
<H2><A NAME="4_3">Custom Data Types</A></H2>
<P>Mini-XML supports custom data types via global load and save
callbacks. Only a single set of callbacks can be active at any time,
however your callbacks can store additional information in order to
support multiple custom data types as needed. The <TT>MXML_CUSTOM</TT>
node type identifies custom data nodes.</P>
<P>The load callback receives a pointer to the current data node and a
string of opaque character data from the XML source with character
entities converted to the corresponding UTF-8 characters. For example,
if we wanted to support a custom date/time type whose value is encoded
as &quot;yyyy-mm-ddThh:mm:ssZ&quot; (ISO format), the load callback would look
like the following:</P>
<PRE>
typedef struct
{
unsigned year, /* Year */
month, /* Month */
day, /* Day */
hour, /* Hour */
minute, /* Minute */
second; /* Second */
time_t unix; /* UNIX time value */
} iso_date_time_t;
int /* I - 0 on success, -1 on error */
load_custom(mxml_node_t *node, /* I - Node */
const char *data) /* I - Value */
{
iso_date_time_t *dt; /* Date/time value */
struct tm tmdata; /* UNIX time data */
/*
* Allocate data structure...
*/
dt = calloc(1, sizeof(iso_date_time_t));
/*
* Try reading 6 unsigned integers from the data string...
*/
if (sscanf(data, &quot;%u-%u-%uT%u:%u:%uZ&quot;,
&amp;(dt-&gt;year), &amp;(dt-&gt;month), &amp;(dt-&gt;day),
&amp;(dt-&gt;hour), &amp;(dt-&gt;minute), &amp;(dt-&gt;second)) != 6)
{
/*
* Unable to read numbers, free the data structure and return an
* error...
*/
free(dt);
return (-1);
}
/*
* Range check values...
*/
if (dt-&gt;month &lt;1 || dt-&gt;month &gt; 12 ||
dt-&gt;day &lt;1 || dt-&gt;day &gt; 31 ||
dt-&gt;hour &lt;0 || dt-&gt;hour &gt; 23 ||
dt-&gt;minute &lt;0 || dt-&gt;minute &gt; 59 ||
dt-&gt;second &lt;0 || dt-&gt;second &gt; 59)
{
/*
* Date information is out of range...
*/
free(dt);
return (-1);
}
/*
* Convert ISO time to UNIX time in seconds...
*/
tmdata.tm_year = dt-&gt;year - 1900;
tmdata.tm_mon = dt-&gt;month - 1;
tmdata.tm_day = dt-&gt;day;
tmdata.tm_hour = dt-&gt;hour;
tmdata.tm_min = dt-&gt;minute;
tmdata.tm_sec = dt-&gt;second;
dt-&gt;unix = gmtime(&amp;tmdata);
/*
* Assign custom node data and destroy function pointers...
*/
node-&gt;value.custom.data = dt;
node-&gt;value.custom.destroy = free;
/*
* Return with no errors...
*/
return (0);
}
</PRE>
<P>The function itself can return 0 on success or -1 if it is unable to
decode the custom data or the data contains an error. Custom data nodes
contain a <TT>void</TT> pointer to the allocated custom data for the
node and a pointer to a destructor function which will free the custom
data when the node is deleted.</P>
<P>The save callback receives the node pointer and returns an allocated
string containing the custom data value. The following save callback
could be used for our ISO date/time type:</P>
<PRE>
char * /* I - Allocated string */
save_custom(mxml_node_t *node) /* I - Node */
{
char data[255]; /* Data string */
iso_date_time_t *dt; /* ISO date/time pointer */
dt = (iso_date_time_t *)node-&gt;custom.data;
snprintf(data, sizeof(data), &quot;%04u-%02u-%02uT%02u:%02u:%02uZ&quot;,
dt-&gt;year, dt-&gt;month, dt-&gt;day, dt-&gt;hour,
dt-&gt;minute, dt-&gt;second);
return (strdup(data));
}
</PRE>
<P>You register the callback functions using the <A href="mxmlSetCustomHandlers.html#mxmlSetCustomHandlers">
<TT>mxmlSetCustomHandlers()</TT></A> function:</P>
<PRE>
mxmlSetCustomHandlers(load_custom, save_custom);
</PRE>
<HR NOSHADE>
<A HREF="toc.html">Contents</A>
<A HREF="SaveCallbacks.html">Previous</A>
<A HREF="ChangingNodeValues.html">Next</A>
</BODY>
</HTML>