Update documentation for mxmldoc changes and use MXML_OPAQUE_CALLBACK for example (Issue #190)

This commit is contained in:
Michael R Sweet 2018-07-02 20:58:30 -04:00
parent 911f74e0d0
commit e19d38b5a7
No known key found for this signature in database
GPG Key ID: 999559A027815955
9 changed files with 1155 additions and 1178 deletions

View File

@ -82,7 +82,7 @@ You load an XML file using the `mxmlLoadFile()` function:
mxml_node_t *tree;
fp = fopen("filename.xml", "r");
tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
tree = mxmlLoadFile(NULL, fp, MXML_OPAQUE_CALLBACK);
fclose(fp);
Similarly, you save an XML file using the `mxmlSaveFile()` function:
@ -102,7 +102,7 @@ functions load XML node trees from and save XML node trees to strings:
mxml_node_t *tree;
...
tree = mxmlLoadString(NULL, buffer, MXML_NO_CALLBACK);
tree = mxmlLoadString(NULL, buffer, MXML_OPAQUE_CALLBACK);
...
mxmlSaveString(tree, buffer, sizeof(buffer), MXML_NO_CALLBACK);

View File

@ -51,41 +51,41 @@ type to return.</p>
child nodes:</p>
<pre>
mxml_type_t
type_cb(mxml_node_t *node)
{
const char *type;
mxml_type_t
type_cb(mxml_node_t *node)
{
const char *type;
/*
* You can lookup attributes and/or use the
* element name, hierarchy, etc...
*/
/*
* You can lookup attributes and/or use the
* element name, hierarchy, etc...
*/
type = mxmlElementGetAttr(node, "type");
if (type == NULL)
type = mxmlGetElement(node);
type = mxmlElementGetAttr(node, "type");
if (type == NULL)
type = mxmlGetElement(node);
if (!strcmp(type, "integer"))
return (MXML_INTEGER);
else if (!strcmp(type, "opaque"))
return (MXML_OPAQUE);
else if (!strcmp(type, "real"))
return (MXML_REAL);
else
return (MXML_TEXT);
}
if (!strcmp(type, "integer"))
return (MXML_INTEGER);
else if (!strcmp(type, "opaque"))
return (MXML_OPAQUE);
else if (!strcmp(type, "real"))
return (MXML_REAL);
else
return (MXML_TEXT);
}
</pre>
<p>To use this callback function, simply use the name when you
call any of the load functions:</p>
<pre>
FILE *fp;
mxml_node_t *tree;
FILE *fp;
mxml_node_t *tree;
fp = fopen("filename.xml", "r");
tree = mxmlLoadFile(NULL, fp, <b>type_cb</b>);
fclose(fp);
fp = fopen("filename.xml", "r");
tree = mxmlLoadFile(NULL, fp, <b>type_cb</b>);
fclose(fp);
</pre>
@ -112,85 +112,85 @@ whitespace to XHTML output to make it more readable in a standard
text editor:</p>
<pre>
const char *
whitespace_cb(mxml_node_t *node,
int where)
{
const char *name;
const char *
whitespace_cb(mxml_node_t *node,
int where)
{
const char *name;
/*
* We can conditionally break to a new line
* before or after any element. These are
* just common HTML elements...
*/
/*
* We can conditionally break to a new line
* before or after any element. These are
* just common HTML elements...
*/
name = mxmlGetElement(node);
name = mxmlGetElement(node);
if (!strcmp(name, "html") ||
!strcmp(name, "head") ||
!strcmp(name, "body") ||
!strcmp(name, "pre") ||
!strcmp(name, "p") ||
!strcmp(name, "h1") ||
!strcmp(name, "h2") ||
!strcmp(name, "h3") ||
!strcmp(name, "h4") ||
!strcmp(name, "h5") ||
!strcmp(name, "h6"))
{
/*
* Newlines before open and after
* close...
*/
if (!strcmp(name, "html") ||
!strcmp(name, "head") ||
!strcmp(name, "body") ||
!strcmp(name, "pre") ||
!strcmp(name, "p") ||
!strcmp(name, "h1") ||
!strcmp(name, "h2") ||
!strcmp(name, "h3") ||
!strcmp(name, "h4") ||
!strcmp(name, "h5") ||
!strcmp(name, "h6"))
{
/*
* Newlines before open and after
* close...
*/
if (where == MXML_WS_BEFORE_OPEN ||
where == MXML_WS_AFTER_CLOSE)
return ("\n");
}
else if (!strcmp(name, "dl") ||
!strcmp(name, "ol") ||
!strcmp(name, "ul"))
{
/*
* Put a newline before and after list
* elements...
*/
if (where == MXML_WS_BEFORE_OPEN ||
where == MXML_WS_AFTER_CLOSE)
return ("\n");
}
else if (!strcmp(name, "dl") ||
!strcmp(name, "ol") ||
!strcmp(name, "ul"))
{
/*
* Put a newline before and after list
* elements...
*/
return ("\n");
}
else if (!strcmp(name, "dd") ||
!strcmp(name, "dt") ||
!strcmp(name, "li"))
{
/*
* Put a tab before &lt;li>'s, * &lt;dd>'s,
* and &lt;dt>'s, and a newline after them...
*/
return ("\n");
}
else if (!strcmp(name, "dd") ||
!strcmp(name, "dt") ||
!strcmp(name, "li"))
{
/*
* Put a tab before &lt;li>'s, * &lt;dd>'s,
* and &lt;dt>'s, and a newline after them...
*/
if (where == MXML_WS_BEFORE_OPEN)
return ("\t");
else if (where == MXML_WS_AFTER_CLOSE)
return ("\n");
}
if (where == MXML_WS_BEFORE_OPEN)
return ("\t");
else if (where == MXML_WS_AFTER_CLOSE)
return ("\n");
}
/*
* Return NULL for no added whitespace...
*/
/*
* Return NULL for no added whitespace...
*/
return (NULL);
}
return (NULL);
}
</pre>
<p>To use this callback function, simply use the name when you
call any of the save functions:</p>
<pre>
FILE *fp;
mxml_node_t *tree;
FILE *fp;
mxml_node_t *tree;
fp = fopen("filename.xml", "w");
mxmlSaveFile(tree, fp, <b>whitespace_cb</b>);
fclose(fp);
fp = fopen("filename.xml", "w");
mxmlSaveFile(tree, fp, <b>whitespace_cb</b>);
fclose(fp);
</pre>
@ -212,97 +212,97 @@ date/time type whose value is encoded as "yyyy-mm-ddThh:mm:ssZ"
following:</p>
<pre>
typedef struct
{
unsigned year, /* Year */
month, /* Month */
day, /* Day */
hour, /* Hour */
minute, /* Minute */
second; /* Second */
time_t unix; /* UNIX time */
} iso_date_time_t;
typedef struct
{
unsigned year, /* Year */
month, /* Month */
day, /* Day */
hour, /* Hour */
minute, /* Minute */
second; /* Second */
time_t unix; /* UNIX time */
} iso_date_time_t;
int
load_custom(mxml_node_t *node,
const char *data)
{
iso_date_time_t *dt;
struct tm tmdata;
int
load_custom(mxml_node_t *node,
const char *data)
{
iso_date_time_t *dt;
struct tm tmdata;
/*
* Allocate data structure...
*/
/*
* Allocate data structure...
*/
dt = calloc(1, sizeof(iso_date_time_t));
dt = calloc(1, sizeof(iso_date_time_t));
/*
* Try reading 6 unsigned integers from the
* data string...
*/
/*
* Try reading 6 unsigned integers from the
* data string...
*/
if (sscanf(data, "%u-%u-%uT%u:%u:%uZ",
&amp;(dt->year), &amp;(dt->month),
&amp;(dt->day), &amp;(dt->hour),
&amp;(dt->minute),
&amp;(dt->second)) != 6)
{
/*
* Unable to read numbers, free the data
* structure and return an error...
*/
if (sscanf(data, "%u-%u-%uT%u:%u:%uZ",
&amp;(dt->year), &amp;(dt->month),
&amp;(dt->day), &amp;(dt->hour),
&amp;(dt->minute),
&amp;(dt->second)) != 6)
{
/*
* Unable to read numbers, free the data
* structure and return an error...
*/
free(dt);
free(dt);
return (-1);
}
return (-1);
}
/*
* Range check values...
*/
/*
* Range check values...
*/
if (dt->month < 1 || dt->month > 12 ||
dt->day < 1 || dt->day > 31 ||
dt->hour < 0 || dt->hour > 23 ||
dt->minute < 0 || dt->minute > 59 ||
dt->second < 0 || dt->second > 59)
{
/*
* Date information is out of range...
*/
if (dt->month < 1 || dt->month > 12 ||
dt->day < 1 || dt->day > 31 ||
dt->hour < 0 || dt->hour > 23 ||
dt->minute < 0 || dt->minute > 59 ||
dt->second < 0 || dt->second > 59)
{
/*
* Date information is out of range...
*/
free(dt);
free(dt);
return (-1);
}
return (-1);
}
/*
* Convert ISO time to UNIX time in
* seconds...
*/
/*
* Convert ISO time to UNIX time in
* seconds...
*/
tmdata.tm_year = dt->year - 1900;
tmdata.tm_mon = dt->month - 1;
tmdata.tm_day = dt->day;
tmdata.tm_hour = dt->hour;
tmdata.tm_min = dt->minute;
tmdata.tm_sec = dt->second;
tmdata.tm_year = dt->year - 1900;
tmdata.tm_mon = dt->month - 1;
tmdata.tm_day = dt->day;
tmdata.tm_hour = dt->hour;
tmdata.tm_min = dt->minute;
tmdata.tm_sec = dt->second;
dt->unix = gmtime(&amp;tmdata);
dt->unix = gmtime(&amp;tmdata);
/*
* Assign custom node data and destroy
* function pointers...
*/
/*
* Assign custom node data and destroy
* function pointers...
*/
mxmlSetCustom(node, data, destroy);
mxmlSetCustom(node, data, destroy);
/*
* Return with no errors...
*/
/*
* Return with no errors...
*/
return (0);
}
return (0);
}
</pre>
<p>The function itself can return 0 on success or -1 if it is
@ -318,22 +318,22 @@ allocated string containing the custom data value. The following
save callback could be used for our ISO date/time type:</p>
<pre>
char *
save_custom(mxml_node_t *node)
{
char data[255];
iso_date_time_t *dt;
char *
save_custom(mxml_node_t *node)
{
char data[255];
iso_date_time_t *dt;
dt = (iso_date_time_t *)mxmlGetCustom(node);
dt = (iso_date_time_t *)mxmlGetCustom(node);
snprintf(data, sizeof(data),
"%04u-%02u-%02uT%02u:%02u:%02uZ",
dt->year, dt->month, dt->day,
dt->hour, dt->minute, dt->second);
snprintf(data, sizeof(data),
"%04u-%02u-%02uT%02u:%02u:%02uZ",
dt->year, dt->month, dt->day,
dt->hour, dt->minute, dt->second);
return (strdup(data));
}
return (strdup(data));
}
</pre>
<p>You register the callback functions using the <a
@ -341,8 +341,8 @@ href='#mxmlSetCustomHandlers'><tt>mxmlSetCustomHandlers()</tt></a>
function:</p>
<pre>
mxmlSetCustomHandlers(<b>load_custom</b>,
<b>save_custom</b>);
mxmlSetCustomHandlers(<b>load_custom</b>,
<b>save_custom</b>);
</pre>
@ -366,9 +366,9 @@ example, use the following function call to change a text node
to contain the text "new" with leading whitespace:</p>
<pre>
mxml_node_t *node;
mxml_node_t *node;
mxmlSetText(node, 1, "new");
mxmlSetText(node, 1, "new");
</pre>
@ -382,10 +382,10 @@ function call to create a new text node containing a constructed
filename:</p>
<pre>
mxml_node_t</a> *node;
mxml_node_t</a> *node;
node = mxmlNewTextf(node, 1, "%s/%s",
path, filename);
node = mxmlNewTextf(node, 1, "%s/%s",
path, filename);
</pre>
@ -408,11 +408,11 @@ structures. The <a href='#mxmlIndexNew'><tt>mxmlIndexNew()</tt></a> function
creates a new index:</p>
<pre>
mxml_node_t *tree;
mxml_index_t *ind;
mxml_node_t *tree;
mxml_index_t *ind;
ind = mxmlIndexNew(tree, "element",
"attribute");
ind = mxmlIndexNew(tree, "element",
"attribute");
</pre>
<p>The first argument is the XML node tree to index. Normally this
@ -441,14 +441,14 @@ function enumerates each of the nodes in the index and can be
used in a loop as follows:</p>
<pre>
mxml_node_t *node;
mxml_node_t *node;
mxmlIndexReset(ind);
mxmlIndexReset(ind);
while ((node = mxmlIndexEnum(ind)) != NULL)
{
// do something with node
}
while ((node = mxmlIndexEnum(ind)) != NULL)
{
// do something with node
}
</pre>
<p>The <a href='#mxmlIndexFind'><tt>mxmlIndexFind()</tt></a>
@ -457,16 +457,16 @@ attribute value in the index. It can be used to find all
matching elements in an index, as follows:</p>
<pre>
mxml_node_t *node;
mxml_node_t *node;
mxmlIndexReset(ind);
mxmlIndexReset(ind);
while ((node = mxmlIndexFind(ind, "element",
"attr-value"))
!= NULL)
{
// do something with node
}
while ((node = mxmlIndexFind(ind, "element",
"attr-value"))
!= NULL)
{
// do something with node
}
</pre>
<p>The second and third arguments represent the element name and
@ -480,7 +480,7 @@ is equivalent to calling <tt>mxmlIndexEnum</tt>.</p>
function:</p>
<pre>
mxmlIndexDelete(ind);
mxmlIndexDelete(ind);
</pre>
<h2>SAX (Stream) Loading of Documents</h2>
@ -502,13 +502,13 @@ process each node as it is read.</p>
a user data pointer you supply:</p>
<pre>
void
sax_cb(mxml_node_t *node,
mxml_sax_event_t event,
void *data)
{
... do something ...
}
void
sax_cb(mxml_node_t *node,
mxml_sax_event_t event,
void *data)
{
... do something ...
}
</pre>
<p>The event will be one of the following:</p>
@ -537,14 +537,14 @@ the following SAX callback will retain all nodes, effectively
simulating a normal in-memory load:</p>
<pre>
void
sax_cb(mxml_node_t *node,
mxml_sax_event_t event,
void *data)
{
if (event != MXML_SAX_ELEMENT_CLOSE)
mxmlRetain(node);
}
void
sax_cb(mxml_node_t *node,
mxml_sax_event_t event,
void *data)
{
if (event != MXML_SAX_ELEMENT_CLOSE)
mxmlRetain(node);
}
</pre>
<p>More typically the SAX callback will only retain a small portion
@ -555,46 +555,46 @@ directives like <tt>&lt;?xml ... ?&gt;</tt> and <tt>&lt;!DOCTYPE ... &gt;</tt>
<!-- NEED 10 -->
<pre>
void
sax_cb(mxml_node_t *node,
mxml_sax_event_t event,
void *data)
void
sax_cb(mxml_node_t *node,
mxml_sax_event_t event,
void *data)
{
if (event == MXML_SAX_ELEMENT_OPEN)
{
/*
* Retain headings and titles...
*/
char *name = mxmlGetElement(node);
if (!strcmp(name, "html") ||
!strcmp(name, "head") ||
!strcmp(name, "title") ||
!strcmp(name, "body") ||
!strcmp(name, "h1") ||
!strcmp(name, "h2") ||
!strcmp(name, "h3") ||
!strcmp(name, "h4") ||
!strcmp(name, "h5") ||
!strcmp(name, "h6"))
mxmlRetain(node);
}
else if (event == MXML_SAX_DIRECTIVE)
mxmlRetain(node);
else if (event == MXML_SAX_DATA)
{
if (mxmlGetRefCount(mxmlGetParent(node)) > 1)
{
if (event == MXML_SAX_ELEMENT_OPEN)
{
/*
* Retain headings and titles...
*/
/*
* If the parent was retained, then retain
* this data node as well.
*/
char *name = mxmlGetElement(node);
if (!strcmp(name, "html") ||
!strcmp(name, "head") ||
!strcmp(name, "title") ||
!strcmp(name, "body") ||
!strcmp(name, "h1") ||
!strcmp(name, "h2") ||
!strcmp(name, "h3") ||
!strcmp(name, "h4") ||
!strcmp(name, "h5") ||
!strcmp(name, "h6"))
mxmlRetain(node);
}
else if (event == MXML_SAX_DIRECTIVE)
mxmlRetain(node);
else if (event == MXML_SAX_DATA)
{
if (mxmlGetRefCount(mxmlGetParent(node)) > 1)
{
/*
* If the parent was retained, then retain
* this data node as well.
*/
mxmlRetain(node);
}
}
mxmlRetain(node);
}
}
}
</pre>
<p>The resulting skeleton document tree can then be searched just
@ -603,30 +603,30 @@ a filter that reads an XHTML document from stdin and then shows the
title and headings in the document would look like:</p>
<pre>
mxml_node_t *doc, *title, *body, *heading;
mxml_node_t *doc, *title, *body, *heading;
doc = mxmlSAXLoadFd(NULL, 0,
MXML_TEXT_CALLBACK,
<b>sax_cb</b>, NULL);
doc = mxmlSAXLoadFd(NULL, 0,
MXML_TEXT_CALLBACK,
<b>sax_cb</b>, NULL);
title = mxmlFindElement(doc, doc, "title",
NULL, NULL,
MXML_DESCEND);
title = mxmlFindElement(doc, doc, "title",
NULL, NULL,
MXML_DESCEND);
if (title)
print_children(title);
if (title)
print_children(title);
body = mxmlFindElement(doc, doc, "body",
NULL, NULL,
MXML_DESCEND);
body = mxmlFindElement(doc, doc, "body",
NULL, NULL,
MXML_DESCEND);
if (body)
{
for (heading = mxmlGetFirstChild(body);
heading;
heading = mxmlGetNextSibling(heading))
print_children(heading);
}
if (body)
{
for (heading = mxmlGetFirstChild(body);
heading;
heading = mxmlGetNextSibling(heading))
print_children(heading);
}
</pre>
</body>

View File

@ -26,14 +26,14 @@ functionality:</p>
<p>Mini-XML provides a single header file which you include:</p>
<pre>
#include &lt;mxml.h&gt;
#include &lt;mxml.h&gt;
</pre>
<p>The Mini-XML library is included with your program using the
<kbd>-lmxml</kbd> option:</p>
<pre>
<kbd>gcc -o myprogram myprogram.c -lmxml ENTER</kbd>
<kbd>gcc -o myprogram myprogram.c -lmxml ENTER</kbd>
</pre>
<p>If you have the <tt>pkg-config(1)</tt> software installed,
@ -41,8 +41,8 @@ you can use it to determine the proper compiler and linker options
for your installation:</p>
<pre>
<kbd>pkg-config --cflags mxml ENTER</kbd>
<kbd>pkg-config --libs mxml ENTER</kbd>
<kbd>pkg-config --cflags mxml ENTER</kbd>
<kbd>pkg-config --libs mxml ENTER</kbd>
</pre>
<h2>Nodes</h2>
@ -55,35 +55,35 @@ sibling nodes (previous and next), and potentially child nodes.</p>
<p>For example, if you have an XML file like the following:</p>
<pre>
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;data&gt;
&lt;node&gt;val1&lt;/node&gt;
&lt;node&gt;val2&lt;/node&gt;
&lt;node&gt;val3&lt;/node&gt;
&lt;group&gt;
&lt;node&gt;val4&lt;/node&gt;
&lt;node&gt;val5&lt;/node&gt;
&lt;node&gt;val6&lt;/node&gt;
&lt;/group&gt;
&lt;node&gt;val7&lt;/node&gt;
&lt;node&gt;val8&lt;/node&gt;
&lt;/data&gt;
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;data&gt;
&lt;node&gt;val1&lt;/node&gt;
&lt;node&gt;val2&lt;/node&gt;
&lt;node&gt;val3&lt;/node&gt;
&lt;group&gt;
&lt;node&gt;val4&lt;/node&gt;
&lt;node&gt;val5&lt;/node&gt;
&lt;node&gt;val6&lt;/node&gt;
&lt;/group&gt;
&lt;node&gt;val7&lt;/node&gt;
&lt;node&gt;val8&lt;/node&gt;
&lt;/data&gt;
</pre>
<p>the node tree for the file would look like the following in memory:</p>
<pre>
?xml version="1.0" encoding="utf-8"?
|
data
|
node - node - node - group - node - node
| | | | | |
val1 val2 val3 | val7 val8
|
node - node - node
| | |
val4 val5 val6
?xml version="1.0" encoding="utf-8"?
|
data
|
node - node - node - group - node - node
| | | | | |
val1 val2 val3 | val7 val8
|
node - node - node
| | |
val4 val5 val6
</pre>
<p>where "-" is a pointer to the sibling node and "|" is a pointer
@ -154,22 +154,22 @@ first and last child nodes for the element, respectively.</p>
<a href="#mxmlGetInteger"><tt>mxmlGetInteger</tt></a> function retrieves the
integer value for a node.</p>
<h3>Opaque Nodes</h3>
<h3>Opaque String Nodes</h3>
<p>Opaque (<tt>MXML_OPAQUE</tt>) nodes are created using the
<p>Opaque string (<tt>MXML_OPAQUE</tt>) nodes are created using the
<a href="#mxmlNewOpaque"><tt>mxmlNewOpaque</tt></a> function. The
<a href="#mxmlGetOpaque"><tt>mxmlGetOpaque</tt></a> function retrieves the
opaque string pointer for a node. Opaque nodes are like string nodes but
preserve all whitespace between nodes.</p>
<h3>Text Nodes</h3>
<h3>Text String Nodes</h3>
<p>Text (<tt>MXML_TEXT</tt>) nodes are created using the
<p>Text string (<tt>MXML_TEXT</tt>) nodes are created using the
<a href="#mxmlNewText"><tt>mxmlNewText</tt></a> and
<a href="#mxmlNewTextf"><tt>mxmlNewTextf</tt></a> functions. Each text node
consists of a text string and (leading) whitespace value - the
consists of a single word string and (leading) whitespace value - the
<a href="#mxmlGetText"><tt>mxmlGetText</tt></a> function retrieves the
text string pointer and whitespace value for a node.</p>
string pointer and whitespace value for a node.</p>
<!-- NEED 12 -->
<h3>Processing Instruction Nodes</h3>
@ -216,35 +216,35 @@ various <tt>mxmlNew</tt> functions. The following code will
create the XML document described in the previous section:</p>
<pre>
mxml_node_t *xml; /* &lt;?xml ... ?&gt; */
mxml_node_t *data; /* &lt;data&gt; */
mxml_node_t *node; /* &lt;node&gt; */
mxml_node_t *group; /* &lt;group&gt; */
mxml_node_t *xml; /* &lt;?xml ... ?&gt; */
mxml_node_t *data; /* &lt;data&gt; */
mxml_node_t *node; /* &lt;node&gt; */
mxml_node_t *group; /* &lt;group&gt; */
xml = mxmlNewXML("1.0");
xml = mxmlNewXML("1.0");
data = mxmlNewElement(xml, "data");
data = mxmlNewElement(xml, "data");
node = mxmlNewElement(data, "node");
mxmlNewText(node, 0, "val1");
node = mxmlNewElement(data, "node");
mxmlNewText(node, 0, "val2");
node = mxmlNewElement(data, "node");
mxmlNewText(node, 0, "val3");
node = mxmlNewElement(data, "node");
mxmlNewText(node, 0, "val1");
node = mxmlNewElement(data, "node");
mxmlNewText(node, 0, "val2");
node = mxmlNewElement(data, "node");
mxmlNewText(node, 0, "val3");
group = mxmlNewElement(data, "group");
group = mxmlNewElement(data, "group");
node = mxmlNewElement(group, "node");
mxmlNewText(node, 0, "val4");
node = mxmlNewElement(group, "node");
mxmlNewText(node, 0, "val5");
node = mxmlNewElement(group, "node");
mxmlNewText(node, 0, "val6");
node = mxmlNewElement(group, "node");
mxmlNewText(node, 0, "val4");
node = mxmlNewElement(group, "node");
mxmlNewText(node, 0, "val5");
node = mxmlNewElement(group, "node");
mxmlNewText(node, 0, "val6");
node = mxmlNewElement(data, "node");
mxmlNewText(node, 0, "val7");
node = mxmlNewElement(data, "node");
mxmlNewText(node, 0, "val8");
node = mxmlNewElement(data, "node");
mxmlNewText(node, 0, "val7");
node = mxmlNewElement(data, "node");
mxmlNewText(node, 0, "val8");
</pre>
<!-- NEED 6 -->
@ -252,7 +252,7 @@ create the XML document described in the previous section:</p>
<a href="#mxmlNewXML"><tt>mxmlNewXML</tt></a> function:</p>
<pre>
xml = mxmlNewXML("1.0");
xml = mxmlNewXML("1.0");
</pre>
<p>We then create the <tt>&lt;data&gt;</tt> node used for this document using
@ -261,7 +261,7 @@ argument specifies the parent node (<tt>xml</tt>) while the second specifies the
element name (<tt>data</tt>):</p>
<pre>
data = mxmlNewElement(xml, "data");
data = mxmlNewElement(xml, "data");
</pre>
<p>Each <tt>&lt;node&gt;...&lt;/node&gt;</tt> in the file is created using the
@ -272,8 +272,8 @@ the text - 0 or false in this case. The last argument specifies the actual text
to add:</p>
<pre>
node = mxmlNewElement(data, "node");
mxmlNewText(node, 0, "val1");
node = mxmlNewElement(data, "node");
mxmlNewText(node, 0, "val1");
</pre>
<p>The resulting in-memory XML document can then be saved or processed just like
@ -287,13 +287,13 @@ href='#mxmlLoadFile'><tt>mxmlLoadFile</tt></a>
function:</p>
<pre>
FILE *fp;
mxml_node_t *tree;
FILE *fp;
mxml_node_t *tree;
fp = fopen("filename.xml", "r");
tree = mxmlLoadFile(NULL, fp,
MXML_TEXT_CALLBACK);
fclose(fp);
fp = fopen("filename.xml", "r");
tree = mxmlLoadFile(NULL, fp,
MXML_OPAQUE_CALLBACK);
fclose(fp);
</pre>
<p>The first argument specifies an existing XML parent node, if
@ -313,24 +313,24 @@ the value type of the immediate children for a new element node:
<tt>MXML_INTEGER</tt>, <tt>MXML_OPAQUE</tt>, <tt>MXML_REAL</tt>,
or <tt>MXML_TEXT</tt>. Load callbacks are described in detail in
<a href='#LOAD_CALLBACKS'>Chapter 3</a>. The example code uses
the <tt>MXML_TEXT_CALLBACK</tt> constant which specifies that all
data nodes in the document contain whitespace-separated text
values. Other standard callbacks include
the <tt>MXML_OPAQUE_CALLBACK</tt> constant which specifies that all
data nodes in the document contain opaque string values with whitespace
preserved. Other standard callbacks include
<tt>MXML_IGNORE_CALLBACK</tt>, <tt>MXML_INTEGER_CALLBACK</tt>,
<tt>MXML_OPAQUE_CALLBACK</tt>, and
<tt>MXML_REAL_CALLBACK</tt>.</p>
<tt>MXML_REAL_CALLBACK</tt>, and
<tt>MXML_TEXT_CALLBACK</tt>.</p>
<p>The <a href='#mxmlLoadString'><tt>mxmlLoadString</tt></a>
function loads XML node trees from a string:</p>
<!-- NEED 10 -->
<pre>
char buffer[8192];
mxml_node_t *tree;
char buffer[8192];
mxml_node_t *tree;
...
tree = mxmlLoadString(NULL, buffer,
MXML_TEXT_CALLBACK);
...
tree = mxmlLoadString(NULL, buffer,
MXML_OPAQUE_CALLBACK);
</pre>
<p>The first and third arguments are the same as used for
@ -347,12 +347,12 @@ is <tt>NULL</tt>.</p>
href='#mxmlSaveFile'><tt>mxmlSaveFile</tt></a> function:</p>
<pre>
FILE *fp;
mxml_node_t *tree;
FILE *fp;
mxml_node_t *tree;
fp = fopen("filename.xml", "w");
mxmlSaveFile(tree, fp, MXML_NO_CALLBACK);
fclose(fp);
fp = fopen("filename.xml", "w");
mxmlSaveFile(tree, fp, MXML_NO_CALLBACK);
fclose(fp);
</pre>
<p>The first argument is the XML node tree to save. It should
@ -376,16 +376,16 @@ and <a href='#mxmlSaveString'><tt>mxmlSaveString</tt></a>
functions save XML node trees to strings:</p>
<pre>
char buffer[8192];
char *ptr;
mxml_node_t *tree;
char buffer[8192];
char *ptr;
mxml_node_t *tree;
...
mxmlSaveString(tree, buffer, sizeof(buffer),
MXML_NO_CALLBACK);
...
mxmlSaveString(tree, buffer, sizeof(buffer),
MXML_NO_CALLBACK);
...
ptr = mxmlSaveAllocString(tree, MXML_NO_CALLBACK);
...
ptr = mxmlSaveAllocString(tree, MXML_NO_CALLBACK);
</pre>
<p>The first and last arguments are the same as used for
@ -405,11 +405,11 @@ href='#mxmlSetWrapMargin'><tt>mxmlSetWrapMargin</tt></a> function
overrides the default wrap margin:</p>
<pre>
/* Set the margin to 132 columns */
mxmlSetWrapMargin(132);
/* Set the margin to 132 columns */
mxmlSetWrapMargin(132);
/* Disable wrapping */
mxmlSetWrapMargin(0);
/* Disable wrapping */
mxmlSetWrapMargin(0);
</pre>
<h2>Memory Management</h2>
@ -420,7 +420,7 @@ free the memory that is used for a particular node or the entire
tree:</p>
<pre>
mxmlDelete(tree);
mxmlDelete(tree);
</pre>
<p>You can also use reference counting to manage memory usage. The
@ -442,13 +442,13 @@ href='#mxmlWalkNext'><tt>mxmlWalkNext</tt></a>functions
can be used to iterate through the XML node tree:</p>
<pre>
mxml_node_t *node;
mxml_node_t *node;
node = mxmlWalkPrev(current, tree,
MXML_DESCEND);
node = mxmlWalkPrev(current, tree,
MXML_DESCEND);
node = mxmlWalkNext(current, tree,
MXML_DESCEND);
node = mxmlWalkNext(current, tree,
MXML_DESCEND);
</pre>
<p>In addition, you can find a named element/node using the <a
@ -456,11 +456,11 @@ href='#mxmlFindElement'><tt>mxmlFindElement</tt></a>
function:</p>
<pre>
mxml_node_t *node;
mxml_node_t *node;
node = mxmlFindElement(tree, tree, "name",
"attr", "value",
MXML_DESCEND);
node = mxmlFindElement(tree, tree, "name",
"attr", "value",
MXML_DESCEND);
</pre>
<p>The <tt>name</tt>, <tt>attr</tt>, and <tt>value</tt>
@ -469,62 +469,62 @@ e.g.:</p>
<!-- NEED 4 -->
<pre>
/* Find the first "a" element */
node = mxmlFindElement(tree, tree, "a",
NULL, NULL,
MXML_DESCEND);
/* Find the first "a" element */
node = mxmlFindElement(tree, tree, "a",
NULL, NULL,
MXML_DESCEND);
</pre>
<!-- NEED 5 -->
<pre>
/* Find the first "a" element with "href"
attribute */
node = mxmlFindElement(tree, tree, "a",
"href", NULL,
MXML_DESCEND);
/* Find the first "a" element with "href"
attribute */
node = mxmlFindElement(tree, tree, "a",
"href", NULL,
MXML_DESCEND);
</pre>
<!-- NEED 6 -->
<pre>
/* Find the first "a" element with "href"
to a URL */
node = mxmlFindElement(tree, tree, "a",
"href",
"http://www.easysw.com/",
MXML_DESCEND);
/* Find the first "a" element with "href"
to a URL */
node = mxmlFindElement(tree, tree, "a",
"href",
"http://www.example.com/",
MXML_DESCEND);
</pre>
<!-- NEED 5 -->
<pre>
/* Find the first element with a "src"
attribute */
node = mxmlFindElement(tree, tree, NULL,
"src", NULL,
MXML_DESCEND);
/* Find the first element with a "src"
attribute */
node = mxmlFindElement(tree, tree, NULL,
"src", NULL,
MXML_DESCEND);
</pre>
<!-- NEED 5 -->
<pre>
/* Find the first element with a "src"
= "foo.jpg" */
node = mxmlFindElement(tree, tree, NULL,
"src", "foo.jpg",
MXML_DESCEND);
/* Find the first element with a "src"
= "foo.jpg" */
node = mxmlFindElement(tree, tree, NULL,
"src", "foo.jpg",
MXML_DESCEND);
</pre>
<p>You can also iterate with the same function:</p>
<pre>
mxml_node_t *node;
mxml_node_t *node;
for (node = mxmlFindElement(tree, tree,
"name",
NULL, NULL,
MXML_DESCEND);
node != NULL;
node = mxmlFindElement(node, tree,
"name",
NULL, NULL,
MXML_DESCEND))
{
... do something ...
}
for (node = mxmlFindElement(tree, tree,
"name",
NULL, NULL,
MXML_DESCEND);
node != NULL;
node = mxmlFindElement(node, tree,
"name",
NULL, NULL,
MXML_DESCEND))
{
... do something ...
}
</pre>
<!-- NEED 10 -->
@ -577,9 +577,9 @@ three constants:</p>
href='#mxmlFindValue'><tt>mxmlFindPath</tt></a>, for example:
<pre>
mxml_node_t *value;
mxml_node_t *value;
value = mxmlFindPath(tree, "path/to/*/foo/bar");
value = mxmlFindPath(tree, "path/to/*/foo/bar");
</pre>
<p>The second argument is a "path" to the parent node. Each component of the

View File

@ -73,46 +73,5 @@ directories:</p>
</pre>
<h2>Creating Mini-XML Packages</h2>
<p>Mini-XML includes two files that can be used to create binary
packages. The first file is <var>mxml.spec</var> which is used
by the <tt>rpmbuild(8)</tt> software to create Red Hat Package
Manager ("RPM") packages which are commonly used on Linux. Since
<tt>rpmbuild</tt> wants to compile the software on its own, you
can provide it with the Mini-XML tar file to build the
package:</p>
<pre>
<kbd>rpmbuild -ta mxml-<i>version</i>.tar.gz ENTER</kbd>
</pre>
<p>The second file is <var>mxml.list</var> which is used by the
<tt>epm(1)</tt> program to create software packages in a variety
of formats. The <tt>epm</tt> program is available from the
following URL:</p>
<pre>
<a href="http://www.epmhome.org/">http://www.epmhome.org/</a>
</pre>
<p>Use the <tt>make</tt> command with the <kbd>epm</kbd> target
to create portable and native packages for your system:</p>
<pre>
<kbd>make epm ENTER</kbd>
</pre>
<p>The packages are stored in a subdirectory named
<var>dist</var> for your convenience. The portable packages
utilize scripts and tar files to install the software on the
target system. After extracting the package archive, use the
<var>mxml.install</var> script to install the software.</p>
<p>The native packages will be in the local OS's native format:
RPM for Red Hat Linux, DPKG for Debian Linux, PKG for Solaris,
and so forth. Use the corresponding commands to install the
native packages.</p>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -578,6 +578,12 @@ const char * mxmlGetText (
.PP
\fBNULL\fR is returned if the node (or its first child) is not a text node.
The "whitespace" argument can be \fBNULL\fR.
.PP
Note: Text nodes consist of whitespace-delimited words. You will only get
single words of text when reading an XML file with \fBMXML_TEXT\fR nodes.
If you want the entire string between elements in the XML file, you MUST read
the XML file with \fBMXML_OPAQUE\fR nodes and get the resulting strings
using the \fImxmlGetOpaque\fR function instead.
.SS mxmlGetType
@ -693,6 +699,12 @@ function returns the value type that should be used for child nodes.
The constants \fBMXML_INTEGER_CALLBACK\fR, \fBMXML_OPAQUE_CALLBACK\fR,
\fBMXML_REAL_CALLBACK\fR, and \fBMXML_TEXT_CALLBACK\fR are defined for
loading child (data) nodes of the specified type.
.PP
Note: The most common programming error when using the Mini-XML library is
to load an XML file using the \fBMXML_TEXT_CALLBACK\fR, which returns inline
text as a series of whitespace-delimited words, instead of using the
\fBMXML_OPAQUE_CALLBACK\fR which returns the inline text as a single string
(including whitespace).
.SS mxmlLoadFile
Load a file into an XML node tree.
.PP
@ -711,6 +723,12 @@ function returns the value type that should be used for child nodes.
The constants \fBMXML_INTEGER_CALLBACK\fR, \fBMXML_OPAQUE_CALLBACK\fR,
\fBMXML_REAL_CALLBACK\fR, and \fBMXML_TEXT_CALLBACK\fR are defined for
loading child (data) nodes of the specified type.
.PP
Note: The most common programming error when using the Mini-XML library is
to load an XML file using the \fBMXML_TEXT_CALLBACK\fR, which returns inline
text as a series of whitespace-delimited words, instead of using the
\fBMXML_OPAQUE_CALLBACK\fR which returns the inline text as a single string
(including whitespace).
.SS mxmlLoadString
Load a string into an XML node tree.
.PP
@ -729,6 +747,12 @@ function returns the value type that should be used for child nodes.
The constants \fBMXML_INTEGER_CALLBACK\fR, \fBMXML_OPAQUE_CALLBACK\fR,
\fBMXML_REAL_CALLBACK\fR, and \fBMXML_TEXT_CALLBACK\fR are defined for
loading child (data) nodes of the specified type.
.PP
Note: The most common programming error when using the Mini-XML library is
to load an XML file using the \fBMXML_TEXT_CALLBACK\fR, which returns inline
text as a series of whitespace-delimited words, instead of using the
\fBMXML_OPAQUE_CALLBACK\fR which returns the inline text as a single string
(including whitespace).
.SS mxmlNewCDATA
Create a new CDATA node.
.PP

Binary file not shown.

View File

@ -26,7 +26,7 @@ header files in the current directory and produce a HTML
documentation file called <var>filename.html</var>:</p>
<pre>
<kbd>mxmldoc *.h *.c &gt;filename.html ENTER</kbd>
<kbd>mxmldoc *.h *.c &gt;filename.html ENTER</kbd>
</pre>
<p>You can also specify an XML file to create which contains all of
@ -35,21 +35,21 @@ command creates an XML file called <var>filename.xml</var> in
addition to the HTML file:</p>
<pre>
<kbd>mxmldoc filename.xml *.h *.c &gt;filename.html ENTER</kbd>
<kbd>mxmldoc filename.xml *.h *.c &gt;filename.html ENTER</kbd>
</pre>
<p>The <tt>--no-output</tt> option disables the normal HTML
output:</p>
<pre>
<kbd>mxmldoc --no-output filename.xml *.h *.c ENTER</kbd>
<kbd>mxmldoc --no-output filename.xml *.h *.c ENTER</kbd>
</pre>
<p>You can then run <tt>mxmldoc</tt> again with the XML file alone
to generate the HTML documentation:</p>
<pre>
<kbd>mxmldoc filename.xml &gt;filename.html ENTER</kbd>
<kbd>mxmldoc filename.xml &gt;filename.html ENTER</kbd>
</pre>
<h3>Creating Man Pages</h3>
@ -58,11 +58,11 @@ to generate the HTML documentation:</p>
create a man page instead of HTML documentation, for example:</p>
<pre>
<kbd>mxmldoc --man filename filename.xml \
&gt;filename.man ENTER</kbd>
<kbd>mxmldoc --man filename filename.xml \
&gt;filename.man ENTER</kbd>
<kbd>mxmldoc --man filename *.h *.c \
&gt;filename.man ENTER</kbd>
<kbd>mxmldoc --man filename *.h *.c \
&gt;filename.man ENTER</kbd>
</pre>
<h3>Creating EPUB Books</h3>
@ -71,24 +71,10 @@ create a man page instead of HTML documentation, for example:</p>
create an EPUB book containing the HTML documentation, for example:</p>
<pre>
<kbd>mxmldoc --epub foo.epub *.h *.c foo.xml ENTER</kbd>
<kbd>mxmldoc --epub foo.epub *.h *.c foo.xml ENTER</kbd>
</pre>
<h3>Creating Xcode Documentation Sets</h3>
<p>The <tt>--docset directory.docset</tt> option tells <tt>mxmldoc</tt> to
create an Xcode documentation set containing the HTML documentation, for
example:</p>
<pre>
<kbd>mxmldoc --docset foo.docset *.h *.c foo.xml ENTER</kbd>
</pre>
<p>Xcode documentation sets can only be built on macOS with Xcode 3.0 or
higher installed.</p>
<h2>Commenting Your Code</h2>
<p>As noted previously, <tt>mxmldoc</tt> looks for in-line comments
@ -107,47 +93,47 @@ example, the following code excerpt defines a key/value structure
and a function that creates a new instance of that structure:</p>
<pre>
/* A key/value pair. This is used with the
dictionary structure. */
/* A key/value pair. This is used with the
dictionary structure. */
struct keyval
{
char *key; /* Key string */
char *val; /* Value string */
};
struct keyval
{
char *key; /* Key string */
char *val; /* Value string */
};
/* Create a new key/value pair. */
/* Create a new key/value pair. */
struct keyval * /* New key/value pair */
new_keyval(
const char *key, /* Key string */
const char *val) /* Value string */
{
...
}
struct keyval * /* New key/value pair */
new_keyval(
const char *key, /* Key string */
const char *val) /* Value string */
{
...
}
</pre>
<p><tt>Mxmldoc</tt> also knows to remove extra asterisks (*) from
the comment string, so the comment string:</p>
<pre>
/*
* Compute the value of PI.
*
* The function connects to an Internet server
* that streams audio of mathematical monks
* chanting the first 100 digits of PI.
*/
/*
* Compute the value of PI.
*
* The function connects to an Internet server
* that streams audio of mathematical monks
* chanting the first 100 digits of PI.
*/
</pre>
<p>will be shown as:</p>
<pre>
Compute the value of PI.
Compute the value of PI.
The function connects to an Internet server
that streams audio of mathematical monks
chanting the first 100 digits of PI.
The function connects to an Internet server
that streams audio of mathematical monks
chanting the first 100 digits of PI.
</pre>
<p><a name="ATDIRECTIVES">Comments</a> can also include the
@ -159,9 +145,9 @@ following special <tt>@name ...@</tt> directive strings:</p>
discourage its use</li>
<li><tt>@exclude format[,...,format]@</tt> - excludes the item from the
documentation in the specified formats: "all" for all formats, "docset"
for Xcode documentation sets, "epub" for EPUB books, "html" for HTML
output, and "man" for man page output</li>
documentation in the specified formats: "all" for all formats, "epub"
for EPUB books, "html" for HTML output, and "man" for man page
output</li>
<li><tt>@private@</tt> - flags the item as private so it
will not be included in the documentation</li>
@ -183,9 +169,9 @@ and introduction text for the generated documentation. The
documentation. The title string is usually put in quotes:</p>
<pre>
<kbd>mxmldoc filename.xml \
--title "My Famous Documentation" \
&gt;filename.html ENTER</kbd>
<kbd>mxmldoc filename.xml \
--title "My Famous Documentation" \
&gt;filename.html ENTER</kbd>
</pre>
<p>The <tt>--section name</tt> option specifies the section for
@ -193,7 +179,7 @@ the documentation. For HTML documentation, the name is placed in
a HTML comment such as:</p>
<pre>
&lt;!-- SECTION: name -->
&lt;!-- SECTION: name -->
</pre>
<p>For man pages, the section name is usually just a number ("3"),
@ -201,7 +187,7 @@ or a number followed by a vendor name ("3acme"). The section name is
used in the <tt>.TH</tt> directive in the man page:</p>
<pre>
.TH mylibrary 3acme "My Title" ...
.TH mylibrary 3acme "My Title" ...
</pre>
<p>The default section name for man page output is "3". There is no

View File

@ -703,7 +703,13 @@ const char *mxmlGetText(<a href="#mxml_node_t">mxml_node_t</a> *node, int *white
<p class="description">Text string or <code>NULL</code></p>
<h4 class="discussion">Discussion</h4>
<p class="discussion"><code>NULL</code> is returned if the node (or its first child) is not a text node.
The &quot;whitespace&quot; argument can be <code>NULL</code>.
The &quot;whitespace&quot; argument can be <code>NULL</code>.<br>
<br>
Note: Text nodes consist of whitespace-delimited words. You will only get
single words of text when reading an XML file with <code>MXML_TEXT</code> nodes.
If you want the entire string between elements in the XML file, you MUST read
the XML file with <code>MXML_OPAQUE</code> nodes and get the resulting strings
using the <a href="#mxmlGetOpaque"><code>mxmlGetOpaque</code></a> function instead.
</p>
<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlGetType">mxmlGetType</a></h3>
@ -845,7 +851,13 @@ single parent node like &lt;?xml&gt; for the entire file. The callback
function returns the value type that should be used for child nodes.
The constants <code>MXML_INTEGER_CALLBACK</code>, <code>MXML_OPAQUE_CALLBACK</code>,
<code>MXML_REAL_CALLBACK</code>, and <code>MXML_TEXT_CALLBACK</code> are defined for
loading child (data) nodes of the specified type.</p>
loading child (data) nodes of the specified type.<br>
<br>
Note: The most common programming error when using the Mini-XML library is
to load an XML file using the <code>MXML_TEXT_CALLBACK</code>, which returns inline
text as a series of whitespace-delimited words, instead of using the
<code>MXML_OPAQUE_CALLBACK</code> which returns the inline text as a single string
(including whitespace).</p>
<h3 class="function"><a id="mxmlLoadFile">mxmlLoadFile</a></h3>
<p class="description">Load a file into an XML node tree.</p>
<p class="code">
@ -868,7 +880,13 @@ single parent node like &lt;?xml&gt; for the entire file. The callback
function returns the value type that should be used for child nodes.
The constants <code>MXML_INTEGER_CALLBACK</code>, <code>MXML_OPAQUE_CALLBACK</code>,
<code>MXML_REAL_CALLBACK</code>, and <code>MXML_TEXT_CALLBACK</code> are defined for
loading child (data) nodes of the specified type.</p>
loading child (data) nodes of the specified type.<br>
<br>
Note: The most common programming error when using the Mini-XML library is
to load an XML file using the <code>MXML_TEXT_CALLBACK</code>, which returns inline
text as a series of whitespace-delimited words, instead of using the
<code>MXML_OPAQUE_CALLBACK</code> which returns the inline text as a single string
(including whitespace).</p>
<h3 class="function"><a id="mxmlLoadString">mxmlLoadString</a></h3>
<p class="description">Load a string into an XML node tree.</p>
<p class="code">
@ -891,7 +909,13 @@ single parent node like &lt;?xml&gt; for the entire string. The callback
function returns the value type that should be used for child nodes.
The constants <code>MXML_INTEGER_CALLBACK</code>, <code>MXML_OPAQUE_CALLBACK</code>,
<code>MXML_REAL_CALLBACK</code>, and <code>MXML_TEXT_CALLBACK</code> are defined for
loading child (data) nodes of the specified type.</p>
loading child (data) nodes of the specified type.<br>
<br>
Note: The most common programming error when using the Mini-XML library is
to load an XML file using the <code>MXML_TEXT_CALLBACK</code>, which returns inline
text as a series of whitespace-delimited words, instead of using the
<code>MXML_OPAQUE_CALLBACK</code> which returns the inline text as a single string
(including whitespace).</p>
<h3 class="function"><span class="info">&#160;Mini-XML 2.3&#160;</span><a id="mxmlNewCDATA">mxmlNewCDATA</a></h3>
<p class="description">Create a new CDATA node.</p>
<p class="code">