📄 mxml.html
字号:
<P>The second argument is the stdio file to write to, as opened by <TT>fopen()</TT> or <TT>popen()</TT>. You can also use <TT>stdout</TT> if you are implementing an XML filter program.</P><P>The third argument is the whitespace callback to use when saving the file. Whitespace callbacks are covered in detail in <A href="SAVE_CALLBACKS">Chapter 3</A>. The previous example code uses the <TT>MXML_NO_CALLBACK</TT> constant to specify that no special whitespace handling is required.</P><P>The <A href="#mxmlSaveAllocString"><TT>mxmlSaveAllocString</TT></A>, 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; ... mxmlSaveString(tree, buffer, sizeof(buffer), MXML_NO_CALLBACK); ... ptr = mxmlSaveAllocString(tree, MXML_NO_CALLBACK);</PRE><P>The first and last arguments are the same as used for <TT>mxmlSaveFile()</TT>. The <TT>mxmlSaveString</TT> function takes pointer and size arguments for saving the XML document to a fixed-size buffer, while <TT>mxmlSaveAllocString()</TT> returns a string buffer that was allocated using <TT>malloc()</TT>.</P><H3><A NAME="3_5_1">Controlling Line Wrapping</A></H3><P>When saving XML documents, Mini-XML normally wraps output lines at column 75 so that the text is readable in terminal windows. The <A href="#mxmlSetWrapMargin"><TT>mxmlSetWrapMargin</TT></A> function overrides the default wrap margin:</P><PRE> /* Set the margin to 132 columns */ mxmlSetWrapMargin(132); /* Disable wrapping */ mxmlSetWrapMargin(0);</PRE><!-- NEW PAGE--><H2><A NAME="3_6">Finding and Iterating Nodes</A></H2><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> mxml_node_t *node; node = mxmlWalkPrev(current, tree, MXML_DESCEND); node = mxmlWalkNext(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> mxml_node_t *node; node = mxmlFindElement(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><!-- NEED 4 --><PRE> /* 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);</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);</PRE><!-- NEED 5 --><PRE> /* 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);</PRE><P>You can also iterate with the same function:</P><PRE> 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 ... }</PRE><!-- NEED 10 --><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.<P>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.<BR><BR></P></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" and "group" elements under the "?xml" parent node in the example above.<P>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.<BR><BR></P></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".<P>If you were to walk from the root node "?xml" to the end of the tree with <TT>mxmlWalkNext()</TT>, the order would be:</P><P><TT>?xml data node val1 node val2 node val3 group node val4 node val5 node val6 node val7 node val8</TT></P><P>If you started at "val8" and walked using <TT>mxmlWalkPrev()</TT>, the order would be reversed, ending at "?xml".</P></LI></UL><HR NOSHADE><H1 align="right"><A name="ADVANCED"><IMG align="right" alt="3" height="100"hspace="10" src="3.gif" width="100"></A>More Mini-XML Programming Techniques</H1><P>This chapter shows additional ways to use the Mini-XML library in your programs.</P><H2><A name="LOAD_CALLBACKS">Load Callbacks</A></H2><P><A href="#LOAD_XML">Chapter 2</A> introduced the <A href="#mxmlLoadFile"><TT>mxmlLoadFile()</TT></A> and <A href="#mxmlLoadString"><TT>mxmlLoadString()</TT></A> functions. The last argument to these functions is a callback function which is used to determine the value type of each data node in an XML document.</P><P>Mini-XML defines several standard callbacks for simple XML data files:</P><UL><LI><TT>MXML_INTEGER_CALLBACK</TT> - All data nodes contain whitespace-separated integers.</LI><LI><TT>MXML_OPAQUE_CALLBACK</TT> - All data nodes contain opaque strings ("CDATA").</LI><LI><TT>MXML_REAL_CALLBACK</TT> - All data nodes contain whitespace-separated floating-point numbers.</LI><LI><TT>MXML_TEXT_CALLBACK</TT> - All data nodes contain whitespace-separated strings.</LI></UL><P>You can provide your own callback functions for more complex XML documents. Your callback function will receive a pointer to the current element node and must return the value type of the immediate children for that element node: <TT>MXML_INTEGER</TT>, <TT>MXML_OPAQUE</TT>, <TT>MXML_REAL</TT>, or <TT>MXML_TEXT</TT>. The 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.</P><!-- NEED 2in --><P>The following callback function looks for an attribute named "type" or the element name to determine the value type for its child nodes:</P><PRE> mxml_type_t type_cb(mxml_node_t *node) { const char *type; /* * You can lookup attributes and/or use the * element name, hierarchy, etc... */ type = mxmlElementGetAttr(node, "type"); if (type == NULL) type = node->value.element.name; 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; fp = fopen("filename.xml", "r"); tree = mxmlLoadFile(NULL, fp, <B>type_cb</B>); fclose(fp);</PRE><H2><A name="SAVE_CALLBACKS">Save Callbacks</A></H2><P><A href="#LOAD_XML">Chapter 2</A> also introduced the <A href="#mxmlSaveFile"><TT>mxmlSaveFile()</TT></A>, <A href="#mxmlSaveString"><TT>mxmlSaveString()</TT></A>, and <A href="#mxmlSaveAllocString"><TT>mxmlSaveAllocString()</TT></A> functions. The last argument to these functions is a callback function which is used to automatically insert whitespace in an XML document.</P><P>Your callback 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 following whitespace callback can be used to add 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; /* * We can conditionally break to a new line * before or after any element. These are * just common HTML elements... */ name = node->value.element.name; 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... */ return ("\n"); } else if (!strcmp(name, "dd") || !strcmp(name, "dt") || !strcmp(name, "li")) { /* * Put a tab before <li>'s, * <dd>'s, * and <dt>'s, and a newline after them... */ 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); }</PRE><P>To use this callback function, simply use the name when you call any of the save functions:</P><PRE>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -