📄 advanced.html
字号:
allocated string containing the custom data value. The followingsave 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; dt = (iso_date_time_t *)node->custom.data; 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)); }</pre><p>You register the callback functions using the <ahref='#mxmlSetCustomHandlers'><tt>mxmlSetCustomHandlers()</tt></a>function:</p><pre> mxmlSetCustomHandlers(<b>load_custom</b>, <b>save_custom</b>);</pre><!-- NEED 20 --><h2>Changing Node Values</h2><p>All of the examples so far have concentrated on creating andloading new XML data nodes. Many applications, however, need tomanipulate or change the nodes during their operation, soMini-XML provides functions to change node values safely andwithout leaking memory.</p><p>Existing nodes can be changed using the <ahref='#mxmlSetElement'><tt>mxmlSetElement()</tt></a>, <ahref='#mxmlSetInteger'><tt>mxmlSetInteger()</tt></a>, <ahref='#mxmlSetOpaque'><tt>mxmlSetOpaque()</tt></a>, <ahref='#mxmlSetReal'><tt>mxmlSetReal()</tt></a>, <ahref='#mxmlSetText'><tt>mxmlSetText()</tt></a>, and <ahref='#mxmlSetTextf'><tt>mxmlSetTextf()</tt></a> functions. Forexample, use the following function call to change a text nodeto contain the text "new" with leading whitespace:</p><pre> mxml_node_t *node; mxmlSetText(node, 1, "new");</pre><h2>Formatted Text</h2><p>The <a href='#mxmlNewTextf'><tt>mxmlNewTextf()</tt></a> and <ahref='#mxmlSetTextf'><tt>mxmlSetTextf()</tt></a> functions createand change text nodes, respectively, using <tt>printf</tt>-styleformat strings and arguments. For example, use the followingfunction call to create a new text node containing a constructedfilename:</p><pre> mxml_node_t</a> *node; node = mxmlNewTextf(node, 1, "%s/%s", path, filename);</pre><h2>Indexing</h2><p>Mini-XML provides functions for managing indices of nodes.The current implementation provides the same functionality as<a href='#mxmlFindElement'><tt>mxmlFindElement()</tt></a>.The advantage of using an index is that searching andenumeration of elements is significantly faster. The onlydisadvantage is that each index is a static snapshot of the XMLdocument, so indices are not well suited to XML data that isupdated more often than it is searched. The overhead of creatingan index is approximately equal to walking the XML documenttree. Nodes in the index are sorted by element name andattribute value.</p><p>Indices are stored in <ahref='#mxml_index_t'><tt>mxml_index_t</tt></a> structures. The<a href='#mxmlIndexNew'><tt>mxmlIndexNew()</tt></a> functioncreates a new index:</p><pre> mxml_node_t *tree; mxml_index_t *ind; ind = mxmlIndexNew(tree, "element", "attribute");</pre><p>The first argument is the XML node tree to index. Normally thiswill be a pointer to the <tt>?xml</tt> element.</p><p>The second argument contains the element to index; passing<tt>NULL</tt> indexes all element nodes alphabetically.</p><p>The third argument contains the attribute to index; passing<tt>NULL</tt> causes only the element name to be indexed.</p><p>Once the index is created, the <ahref='#mxmlIndexEnum'><tt>mxmlIndexEnum()</tt></a>, <ahref='#mxmlIndexFind'><tt>mxmlIndexFind()</tt></a>, and <ahref='#mxmlIndexReset'><tt>mxmlIndexReset()</tt></a> functionsare used to access the nodes in the index. The <ahref='#mxmlIndexReset'><tt>mxmlIndexReset()</tt></a> functionresets the "current" node pointer in the index, allowing you todo new searches and enumerations on the same index. Typicallyyou will call this function prior to your calls to <ahref='#mxmlIndexEnum'><tt>mxmlIndexEnum()</tt></a> and <ahref='#mxmlIndexFind'><tt>mxmlIndexFind()</tt></a>.</p><p>The <a href='#mxmlIndexEnum'><tt>mxmlIndexEnum()</tt></a>function enumerates each of the nodes in the index and can beused in a loop as follows:</p><pre> mxml_node_t *node; mxmlIndexReset(ind); while ((node = mxmlIndexEnum(ind)) != NULL) { // do something with node }</pre><p>The <a href='#mxmlIndexFind'><tt>mxmlIndexFind()</tt></a>function locates the next occurrence of the named element andattribute value in the index. It can be used to find allmatching elements in an index, as follows:</p><pre> mxml_node_t *node; mxmlIndexReset(ind); while ((node = mxmlIndexFind(ind, "element", "attr-value")) != NULL) { // do something with node }</pre><p>The second and third arguments represent the element name andattribute value, respectively. A <tt>NULL</tt> pointer is usedto return all elements or attributes in the index. Passing<tt>NULL</tt> for both the element name and attribute valueis equivalent to calling <tt>mxmlIndexEnum</tt>.</p><p>When you are done using the index, delete it using the<a href='#mxmlIndexDelete()'><tt>mxmlIndexDelete()</tt></a>function:</p><pre> mxmlIndexDelete(ind);</pre><h2>SAX (Stream) Loading of Documents</h2><p>Mini-XML supports an implementation of the Simple API for XML(SAX) which allows you to load and process an XML document as astream of nodes. Aside from allowing you to process XML documents ofany size, the Mini-XML implementation also allows you to retainportions of the document in memory for later processing.</p><p>The <a href='#mxmlSAXLoad'><tt>mxmlSAXLoadFd</tt></a>, <ahref='#mxmlSAXLoadFile'><tt>mxmlSAXLoadFile</tt></a>, and <ahref='#mxmlSAXLoadString'><tt>mxmlSAXLoadString</tt></a> functionsprovide the SAX loading APIs. Each function works like thecorresponding <tt>mxmlLoad</tt> function but uses a callback toprocess each node as it is read.</p><p>The callback function receives the node, an event code, anda user data pointer you supply:</p><pre> 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><ul> <li><tt>MXML_SAX_CDATA</tt> - CDATA was just read</li> <li><tt>MXML_SAX_COMMENT</tt> - A comment was just read</li> <li><tt>MXML_SAX_DATA</tt> - Data (custom, integer, opaque, real, or text) was just read</li> <li><tt>MXML_SAX_DIRECTIVE</tt> - A processing directive was just read</li> <li><tt>MXML_SAX_ELEMENT_CLOSE</tt> - An open element was just read (<tt><element></tt>)</li> <li><tt>MXML_SAX_ELEMENT_OPEN</tt> - A close element was just read (<tt></element></tt>)</li></ul><p>Elements are <em>released</em> after the close element isprocessed. All other nodes are released after they are processed.The SAX callback can <em>retain</em> the node using the <ahref='#mxmlRetain'><tt>mxmlRetain</tt></a> function. For example,the following SAX callback will retain all nodes, effectivelysimulating 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); }</pre><p>More typically the SAX callback will only retain a small portionof the document that is needed for post-processing. For example, thefollowing SAX callback will retain the title and headings in anXHTML file. It also retains the (parent) elements like <tt><html></tt>, <tt><head></tt>, and <tt><body></tt>, and processingdirectives like <tt><?xml ... ?></tt> and <tt><!DOCTYPE ... ></tt>:</p><!-- NEED 10 --><pre> 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 = node->value.element.name; 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 && node->parent->ref_count > 1) { /* * If the parent was retained, then retain * this data node as well. */ mxmlRetain(node); } }</pre><p>The resulting skeleton document tree can then be searched justlike one loaded using the <tt>mxmlLoad</tt> functions. For example,a filter that reads an XHTML document from stdin and then shows thetitle and headings in the document would look like:</p><pre> mxml_node_t *doc, *title, *body, *heading; doc = mxmlSAXLoadFd(NULL, 0, MXML_TEXT_CALLBACK, <b>sax_cb</b>, NULL); title = mxmlFindElement(doc, doc, "title", NULL, NULL, MXML_DESCEND); if (title) print_children(title); body = mxmlFindElement(doc, doc, "body", NULL, NULL, MXML_DESCEND); if (body) { for (heading = body->child; heading; heading = heading->next) print_children(heading); }</pre></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -