mxml/doc/basics.html
Michael R Sweet cf3827d52a Poll stuff.
2004-05-20 03:38:42 +00:00

300 lines
9.0 KiB
HTML

<html>
<body>
<h1 align='right'><a name='BASICS'>2 - Getting Started with
Mini-XML</a></h1>
<p>This chapter describes how to write programs that use
Mini-XML to access data in an XML file.</p>
<h2>The Basics</h2>
<p>Mini-XML provides a single header file which you include:</p>
<pre>
#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>
</pre>
<p>If you have the <tt>pkg-config(1)</tt> software installed,
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>
</pre>
<h2>Nodes</h2>
<p>Every piece of information in an XML file (elements, text,
numbers) is stored in memory in "nodes". Nodes are defined by
the <a
href='#mxml_node_t'><tt>mxml_node_t</tt></a>
structure. The <a
href='#mxml_type_t'><tt>type</tt></a> member
defines the node type (element, integer, opaque, real, or text)
which determines which value you want to look at in the <a
href='#mxml_value_t'><tt>value</tt></a> union.</p>
<p>New nodes can be created using the <a
href='#mxmlNewElement'><tt>mxmlNewElement()</tt></a>,
<a
href='#mxmlNewInteger'><tt>mxmlNewInteger()</tt></a>,
<a
href='#mxmlNewOpaque'><tt>mxmlNewOpaque()</tt></a>,
<a href='#mxmlNewReal'><tt>mxmlNewReal()</tt></a>,
and <a
href='#mxmlNewText'><tt>mxmlNewText()</tt></a>
functions. Only elements can have child nodes, and the top node
must be an element, usually "?xml".</p>
<p>Each node has pointers for the node above (<tt>parent</tt>),
below (<tt>child</tt>), to the left (<tt>prev</tt>), and to the
right (<tt>next</tt>) of the current node. If you have an XML
file like the following:</p>
<pre>
&lt;?xml version="1.0"?&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;node&gt;val9&lt;/node&gt;
&lt;/data&gt;
</pre>
<p>the node tree returned by <tt>mxmlLoadFile()</tt> would look
like the following in memory:</p>
<pre>
?xml
|
data
|
node - node - node - group - node - node - node
| | | | | | |
val1 val2 val3 | val7 val8 val9
|
node - node - node
| | |
val4 val5 val6
</pre>
<p>where "-" is a pointer to the next node and "|" is a pointer
to the first child node.</p>
<p>Once you are done with the XML data, use the <a
href='#mxmlDelete'><tt>mxmlDelete()</tt></a>
function to recursively free the memory that is used for a
particular node or the entire tree:</p>
<pre>
mxmlDelete(tree);
</pre>
<h2>Loading and Saving XML Files</h2>
<p>You load an XML file using the <a
href='#mxmlLoadFile'><tt>mxmlLoadFile()</tt></a>
function:</p>
<pre>
FILE *fp;
<a href='#mxml_node_t'>mxml_node_t</a> *tree;
fp = fopen("filename.xml", "r");
tree = <a href='#mxmlLoadFile'>mxmlLoadFile</a>(NULL, fp, MXML_NO_CALLBACK);
fclose(fp);
</pre>
<p>The third argument specifies a callback function which
returns 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>. This function is
called <i>after</i> the element and its attributes have been
read, so you can look at the element name, attributes, and
attribute values to determine the proper value type to return.
The default value type is MXML_TEXT if no callback is used.</p>
<p>Similarly, you save an XML file using the <a
href='#mxmlSaveFile'><tt>mxmlSaveFile()</tt></a>
function:</p>
<pre>
FILE *fp;
<a href='#mxml_node_t'>mxml_node_t</a> *tree;
fp = fopen("filename.xml", "w");
<a href='#mxmlSaveFile'>mxmlSaveFile</a>(tree, fp, MXML_NO_CALLBACK);
fclose(fp);
</pre>
<p>Callback functions for saving are used to optionally insert
whitespace before and after elements in the node tree. Your
function will be called up to four times for each element node
with a pointer to the node and a "where" value of
<tt>MXML_WS_BEFORE_OPEN</tt>, <tt>MXML_WS_AFTER_OPEN</tt>,
<tt>MXML_WS_BEFORE_CLOSE</tt>, or <tt>MXML_WS_AFTER_CLOSE</tt>.
The callback function should return <tt>NULL</tt> if no
whitespace should be added and the string to insert (spaces,
tabs, carriage returns, and newlines) otherwise.</p>
<p>The <a
href='#mxmlLoadString'><tt>mxmlLoadString()</tt></a>,
<a
href='#mxmlSaveAllocString'><tt>mxmlSaveAllocString()</tt></a>,
and <a
href='#mxmlSaveString'><tt>mxmlSaveString()</tt></a>
functions load XML node trees from and save XML node trees to
strings:</p>
<pre>
char buffer[8192];
char *ptr;
<a href='#mxml_node_t'>mxml_node_t</a> *tree;
...
tree = <a href='#mxmlLoadString'>mxmlLoadString</a>(NULL, buffer, MXML_NO_CALLBACK);
...
<a href='#mxmlSaveString'>mxmlSaveString</a>(tree, buffer, sizeof(buffer), MXML_NO_CALLBACK);
...
ptr = <a href='#mxmlSaveAllocString'>mxmlSaveAllocString</a>(tree, MXML_NO_CALLBACK);
</pre>
<h3>Finding and Iterating Nodes</h3>
<p>The <a
href='#mxmlWalkPrev'><tt>mxmlWalkPrev()</tt></a>
and <a
href='#mxmlWalkNext'><tt>mxmlWalkNext()</tt></a>functions
can be used to iterate through the XML node tree:</p>
<pre>
<a href='#mxml_node_t'>mxml_node_t</a> *node = <a href='#mxmlWalkPrev'>mxmlWalkPrev</a>(current, tree, MXML_DESCEND);
<a href='#mxml_node_t'>mxml_node_t</a> *node = <a href='#mxmlWalkNext'>mxmlWalkNext</a>(current, tree, MXML_DESCEND);
</pre>
<p>In addition, you can find a named element/node using the <a
href='#mxmlFindElement'><tt>mxmlFindElement()</tt></a>
function:</p>
<pre>
<a href='#mxml_node_t'>mxml_node_t</a> *node = <a href='#mxmlFindElement'>mxmlFindElement</a>(tree, tree, "name", "attr",
"value", MXML_DESCEND);
</pre>
<p>The <tt>name</tt>, <tt>attr</tt>, and <tt>value</tt>
arguments can be passed as <tt>NULL</tt> to act as wildcards,
e.g.:</p>
<pre>
/* Find the first "a" element */
node = <a href='#mxmlFindElement'>mxmlFindElement</a>(tree, tree, "a", NULL, NULL, MXML_DESCEND);
/* Find the first "a" element with "href" attribute */
node = <a href='#mxmlFindElement'>mxmlFindElement</a>(tree, tree, "a", "href", NULL, MXML_DESCEND);
/* Find the first "a" element with "href" to a URL */
node = <a href='#mxmlFindElement'>mxmlFindElement</a>(tree, tree, "a", "href",
"http://www.easysw.com/~mike/mxml/", MXML_DESCEND);
/* Find the first element with a "src" attribute*/
node = <a href='#mxmlFindElement'>mxmlFindElement</a>(tree, tree, NULL, "src", NULL, MXML_DESCEND);
/* Find the first element with a "src" = "foo.jpg" */
node = <a href='#mxmlFindElement'>mxmlFindElement</a>(tree, tree, NULL, "src", "foo.jpg", MXML_DESCEND);
</pre>
<p>You can also iterate with the same function:</p>
<pre>
<a href='#mxml_node_t'>mxml_node_t</a> *node;
for (node = <a href='#mxmlFindElement'>mxmlFindElement</a>(tree, tree, "name", NULL, NULL, MXML_DESCEND);
node != NULL;
node = <a href='#mxmlFindElement'>mxmlFindElement</a>(node, tree, "name", NULL, NULL, MXML_DESCEND))
{
... do something ...
}
</pre>
<p>The <tt>MXML_DESCEND</tt> argument can actually be one of
three constants:</p>
<ul>
<li><tt>MXML_NO_DESCEND</tt> means to not to look at any
child nodes in the element hierarchy, just look at
siblings at the same level or parent nodes until the top
node or top-of-tree is reached. The previous node from
"group" would be the "node" element to the left, while
the next node from "group" would be the "node" element
to the right.</li>
<li><tt>MXML_DESCEND_FIRST</tt> means that it is OK to
descend to the first child of a node, but not to descend
further when searching. You'll normally use this when
iterating through direct children of a parent node, e.g.
all of the "node" elements under the "?xml" parent node
in the example above. This mode is only applicable to
the search function; the walk functions treat this as
<tt>MXML_DESCEND</tt> since every call is a first
time.</li>
<li><tt>MXML_DESCEND</tt> means to keep descending until
you hit the bottom of the tree. The previous node from
"group" would be the "val3" node and the next node would
be the first node element under "group". If you were to
walk from the root node "?xml" to the end of the
tree with <tt>mxmlWalkNext()</tt>, the order would be:
<pre>
?xml
data
node
val1
node
val2
node
val3
group
node
val4
node
val5
node
val6
node
val7
node
val8
node
val9
</pre>
<p>If you started at "val9" and walked using
<tt>mxmlWalkPrev()</tt>, the order would be reversed,
ending at "?xml".</p></li>
</ul>
</body>
</html>