Add mxmlNewXML() function and use it.

More updates to the manual.
pull/193/head
Michael R Sweet 18 years ago
parent 94ad843d35
commit 0f8052e766
  1. 25
      CHANGES
  2. 196
      doc/advanced.html
  3. 260
      doc/basics.html
  4. 24
      doc/reference.html
  5. 46
      doc/relnotes.html
  6. 23
      mxml-node.c
  7. 1
      mxml.h
  8. 16
      mxml.xml
  9. 2
      mxmldoc.c
  10. 2
      testmxml.c

@ -1,11 +1,12 @@
CHANGES - 2007-04-18 CHANGES - 2007-04-19
-------------------- --------------------
CHANGES IN Mini-XML 2.3 CHANGES IN Mini-XML 2.3
- Added two exceptions to the LGPL to support static - Added two exceptions to the LGPL to support static
linking of applications against Mini-XML. linking of applications against Mini-XML
- Added mxmlElementSetAttrf() function (STR #43) - Added a mxmlNewXML() function
- Added a mxmlElementSetAttrf() function (STR #43)
- Added snprintf() emulation function for test program (STR - Added snprintf() emulation function for test program (STR
#32) #32)
- Added the _CRT_SECURE_NO_DEPRECATE definition when - Added the _CRT_SECURE_NO_DEPRECATE definition when
@ -15,31 +16,31 @@ CHANGES IN Mini-XML 2.3
- mxmlLoad*() did not detect missing close tags at the end - mxmlLoad*() did not detect missing close tags at the end
of an XML document (STR #45) of an XML document (STR #45)
- Added user_data and ref_count members to mxml_node_t - Added user_data and ref_count members to mxml_node_t
structure. structure
- Added mxmlReleaseNode() and mxmlRetainNode() APIs for - Added mxmlReleaseNode() and mxmlRetainNode() APIs for
reference-counted nodes. reference-counted nodes
- Added mxmlSetWrapMargin() to control the wrapping of XML - Added mxmlSetWrapMargin() to control the wrapping of XML
output. output
- Added conditional check for EINTR error code for - Added conditional check for EINTR error code for
certain Windows compilers that do not define it (STR certain Windows compilers that do not define it (STR
#33) #33)
- The mxmldoc program now generates correct HTML 4.0 - The mxmldoc program now generates correct HTML 4.0
output (previously it generated invalid XHTML...) output - previously it generated invalid XHTML
- The mxmldoc program now supports "@deprecated@, - The mxmldoc program now supports "@deprecated@,
"@private@", and "@since version@" comments. "@private@", and "@since version@" comments
- Fixed function and enumeration type bugs in mxmldoc. - Fixed function and enumeration type bugs in mxmldoc.
- Fixed XML schema for mxmldoc. - Fixed the XML schema for mxmldoc
- The mxmldoc program now supports --intro, --section, - The mxmldoc program now supports --intro, --section,
and --title options. and --title options
- The mxmlLoad*() functions could leak a node on an error - The mxmlLoad*() functions could leak a node on an error
(STR #27) (STR #27)
- The mxml_vsnprintf() function could get in an infinite - The mxml_vsnprintf() function could get in an infinite
loop on a buffer overflow (STR #25) loop on a buffer overflow (STR #25)
- Added new mxmlNewCDATA() and mxmlSetCDATA() functions - Added new mxmlNewCDATA() and mxmlSetCDATA() functions
to create and set CDATA nodes, which are really just to create and set CDATA nodes, which are really just
special element nodes. special element nodes
- Added new MXML_IGNORE type and MXML_IGNORE_CB callback - Added new MXML_IGNORE type and MXML_IGNORE_CB callback
to ignore non-element nodes (i.e. whitespace) to ignore non-element nodes, e.g. whitespace
- mxmlLoad*() crashed when reporting an error in some - mxmlLoad*() crashed when reporting an error in some
invalid XML (STR #23) invalid XML (STR #23)

@ -21,11 +21,11 @@ XML data files:</p>
<ul> <ul>
<li><tt>MXML_INTEGER_CALLBACK</tt> - All data nodes contain <li><tt>MXML_INTEGER_CALLBACK</tt> - All data nodes
whitespace-separated integers.</li> contain whitespace-separated integers.</li>
<li><tt>MXML_OPAQUE_CALLBACK</tt> - All data nodes contain <li><tt>MXML_OPAQUE_CALLBACK</tt> - All data nodes
opaque strings ("CDATA").</li> contain opaque strings ("CDATA").</li>
<li><tt>MXML_REAL_CALLBACK</tt> - All data nodes contain <li><tt>MXML_REAL_CALLBACK</tt> - All data nodes contain
whitespace-separated floating-point numbers.</li> whitespace-separated floating-point numbers.</li>
@ -51,21 +51,18 @@ type to return.</p>
child nodes:</p> child nodes:</p>
<pre> <pre>
/* mxml_type_t
* 'type_cb()' - XML data type callback for mxmlLoadFile()... type_cb(mxml_node_t *node)
*/
mxml_type_t /* O - Data type */
type_cb(mxml_node_t *node) /* I - Element node */
{ {
const char *type; /* Type string */ 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...
*/ */
if ((type = mxmlElementGetAttr(node, "type")) == NULL) type = mxmlElementGetAttr(node, "type");
if (type == NULL)
type = node->value.element.name; type = node->value.element.name;
if (!strcmp(type, "integer")) if (!strcmp(type, "integer"))
@ -84,10 +81,10 @@ call any of the load functions:</p>
<pre> <pre>
FILE *fp; FILE *fp;
<a href='#mxml_node_t'>mxml_node_t</a> *tree; mxml_node_t *tree;
fp = fopen("filename.xml", "r"); fp = fopen("filename.xml", "r");
tree = <a href='#mxmlLoadFile'>mxmlLoadFile</a>(NULL, fp, <b>type_cb</b>); tree = mxmlLoadFile(NULL, fp, <b>type_cb</b>);
fclose(fp); fclose(fp);
</pre> </pre>
@ -108,54 +105,66 @@ 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>. <tt>MXML_WS_BEFORE_CLOSE</tt>, or <tt>MXML_WS_AFTER_CLOSE</tt>.
The callback function should return <tt>NULL</tt> if no The callback function should return <tt>NULL</tt> if no
whitespace should be added and the string to insert (spaces, whitespace should be added and the string to insert (spaces,
tabs, carriage returns, and newlines) otherwise. The following tabs, carriage returns, and newlines) otherwise.</p>
whitespace callback can be used to add whitespace to XHTML
output to make it more readable in a standard text editor:</p>
<!-- NEW PAGE --> <p>The following whitespace callback can be used to add
<pre> whitespace to XHTML output to make it more readable in a standard
/* text editor:</p>
* 'whitespace_cb()' - Let the mxmlSaveFile() function know when to insert
* newlines and tabs...
*/
const char * /* O - Whitespace string or NULL */ <pre>
whitespace_cb(mxml_node_t *node, /* I - Element node */ const char *
int where) /* I - Open or close tag? */ whitespace_cb(mxml_node_t *node,
int where)
{ {
const char *name; /* Name of element */ const char *name;
/* /*
* We can conditionally break to a new line before or after any element. * We can conditionally break to a new line
* These are just common HTML elements... * before or after any element. These are
* just common HTML elements...
*/ */
name = node->value.element.name; name = node->value.element.name;
if (!strcmp(name, "html") || !strcmp(name, "head") || !strcmp(name, "body") || if (!strcmp(name, "html") ||
!strcmp(name, "pre") || !strcmp(name, "p") || !strcmp(name, "head") ||
!strcmp(name, "h1") || !strcmp(name, "h2") || !strcmp(name, "h3") || !strcmp(name, "body") ||
!strcmp(name, "h4") || !strcmp(name, "h5") || !strcmp(name, "h6")) !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... * Newlines before open and after
* close...
*/ */
if (where == MXML_WS_BEFORE_OPEN || where == MXML_WS_AFTER_CLOSE) if (where == MXML_WS_BEFORE_OPEN ||
where == MXML_WS_AFTER_CLOSE)
return ("\n"); return ("\n");
} }
else if (!strcmp(name, "dl") || !strcmp(name, "ol") || !strcmp(name, "ul")) else if (!strcmp(name, "dl") ||
!strcmp(name, "ol") ||
!strcmp(name, "ul"))
{ {
/* /*
* Put a newline before and after list elements... * Put a newline before and after list
* elements...
*/ */
return ("\n"); return ("\n");
} }
else if (!strcmp(name, "dd") || !strcmp(name, "dt") || !strcmp(name, "li")) 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... * 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) if (where == MXML_WS_BEFORE_OPEN)
@ -172,20 +181,20 @@ output to make it more readable in a standard text editor:</p>
} }
</pre> </pre>
<!-- NEW PAGE -->
<p>To use this callback function, simply use the name when you <p>To use this callback function, simply use the name when you
call any of the save functions:</p> call any of the save functions:</p>
<pre> <pre>
FILE *fp; FILE *fp;
<a href='#mxml_node_t'>mxml_node_t</a> *tree; mxml_node_t *tree;
fp = fopen("filename.xml", "w"); fp = fopen("filename.xml", "w");
<a href='#mxmlSaveFile'>mxmlSaveFile</a>(tree, fp, whitespace_cb); mxmlSaveFile(tree, fp, <b>whitespace_cb</b>);
fclose(fp); fclose(fp);
</pre> </pre>
<!-- NEED 10 -->
<h2>Custom Data Types</h2> <h2>Custom Data Types</h2>
<p>Mini-XML supports custom data types via global load and save <p>Mini-XML supports custom data types via global load and save
@ -211,16 +220,15 @@ following:</p>
hour, /* Hour */ hour, /* Hour */
minute, /* Minute */ minute, /* Minute */
second; /* Second */ second; /* Second */
time_t unix; /* UNIX time value */ time_t unix; /* UNIX time */
} iso_date_time_t; } iso_date_time_t;
int /* I - 0 on success, -1 on error */ int
load_custom(mxml_node_t *node, /* I - Node */ load_custom(mxml_node_t *node,
const char *data) /* I - Value */ const char *data)
{ {
iso_date_time_t *dt; /* Date/time value */ iso_date_time_t *dt;
struct tm tmdata; /* UNIX time data */ struct tm tmdata;
/* /*
* Allocate data structure... * Allocate data structure...
@ -229,16 +237,19 @@ following:</p>
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", if (sscanf(data, "%u-%u-%uT%u:%u:%uZ",
&(dt->year), &(dt->month), &(dt->day), &(dt->year), &(dt->month),
&(dt->hour), &(dt->minute), &(dt->second)) != 6) &(dt->day), &(dt->hour),
&(dt->minute),
&(dt->second)) != 6)
{ {
/* /*
* Unable to read numbers, free the data structure and return an * Unable to read numbers, free the data
* error... * structure and return an error...
*/ */
free(dt); free(dt);
@ -266,7 +277,8 @@ following:</p>
} }
/* /*
* Convert ISO time to UNIX time in seconds... * Convert ISO time to UNIX time in
* seconds...
*/ */
tmdata.tm_year = dt->year - 1900; tmdata.tm_year = dt->year - 1900;
@ -276,10 +288,11 @@ following:</p>
tmdata.tm_min = dt->minute; tmdata.tm_min = dt->minute;
tmdata.tm_sec = dt->second; tmdata.tm_sec = dt->second;
dt->unix = gmtime(&tmdata); dt->unix = gmtime(&amp;tmdata);
/* /*
* Assign custom node data and destroy function pointers... * Assign custom node data and destroy
* function pointers...
*/ */
node->value.custom.data = dt; node->value.custom.data = dt;
@ -300,24 +313,24 @@ allocated custom data for the node and a pointer to a destructor
function which will free the custom data when the node is function which will free the custom data when the node is
deleted.</p> deleted.</p>
<!-- NEED 3in -->
<p>The save callback receives the node pointer and returns an <p>The save callback receives the node pointer and returns an
allocated string containing the custom data value. The following allocated string containing the custom data value. The following
save callback could be used for our ISO date/time type:</p> save callback could be used for our ISO date/time type:</p>
<pre> <pre>
char * /* I - Allocated string */ char *
save_custom(mxml_node_t *node) /* I - Node */ save_custom(mxml_node_t *node)
{ {
char data[255]; /* Data string */ char data[255];
iso_date_time_t *dt; /* ISO date/time pointer */ iso_date_time_t *dt;
dt = (iso_date_time_t *)node->custom.data; dt = (iso_date_time_t *)node->custom.data;
snprintf(data, sizeof(data), "%04u-%02u-%02uT%02u:%02u:%02uZ", snprintf(data, sizeof(data),
dt->year, dt->month, dt->day, dt->hour, "%04u-%02u-%02uT%02u:%02u:%02uZ",
dt->minute, dt->second); dt->year, dt->month, dt->day,
dt->hour, dt->minute, dt->second);
return (strdup(data)); return (strdup(data));
} }
@ -328,7 +341,8 @@ href='#mxmlSetCustomHandlers'><tt>mxmlSetCustomHandlers()</tt></a>
function:</p> function:</p>
<pre> <pre>
mxmlSetCustomHandlers(load_custom, save_custom); mxmlSetCustomHandlers(<b>load_custom</b>,
<b>save_custom</b>);
</pre> </pre>
@ -344,30 +358,32 @@ without leaking memory.</p>
href='#mxmlSetElement'><tt>mxmlSetElement()</tt></a>, <a href='#mxmlSetElement'><tt>mxmlSetElement()</tt></a>, <a
href='#mxmlSetInteger'><tt>mxmlSetInteger()</tt></a>, <a href='#mxmlSetInteger'><tt>mxmlSetInteger()</tt></a>, <a
href='#mxmlSetOpaque'><tt>mxmlSetOpaque()</tt></a>, <a href='#mxmlSetOpaque'><tt>mxmlSetOpaque()</tt></a>, <a
href='#mxmlSetReal'><tt>mxmlSetReal()</tt></a>, and <a href='#mxmlSetReal'><tt>mxmlSetReal()</tt></a>, <a
href='#mxmlSetText'><tt>mxmlSetText()</tt></a> functions. For href='#mxmlSetText'><tt>mxmlSetText()</tt></a>, and <a
href='#mxmlSetTextf'><tt>mxmlSetTextf()</tt></a> functions. For
example, use the following function call to change a text node example, use the following function call to change a text node
to contain the text "new" with leading whitespace:</p> to contain the text "new" with leading whitespace:</p>
<pre> <pre>
<a href='#mxml_node_t'>mxml_node_t</a> *node; mxml_node_t *node;
<a href='#mxmlSetText'>mxmlSetText</a>(node, 1, "new"); mxmlSetText(node, 1, "new");
</pre> </pre>
<h2>Formatted Text</h2> <h2>Formatted Text</h2>
<p>The <a href='#mxmlNewTextf'><tt>mxmlNewTextf()</tt></a> and <p>The <a href='#mxmlNewTextf'><tt>mxmlNewTextf()</tt></a> and <a
<a href='#mxmlSetTextf'><tt>mxmlSetTextf()</tt></a> functions href='#mxmlSetTextf'><tt>mxmlSetTextf()</tt></a> functions create
create and change text nodes, respectively, using and change text nodes, respectively, using <tt>printf</tt>-style
<tt>printf</tt>-style format strings and arguments. For example, format strings and arguments. For example, use the following
use the following function call to create a new text node:</p> function call to create a new text node containing a constructed
filename:</p>
<pre> <pre>
<a href='#mxml_node_t'>mxml_node_t</a> *node; mxml_node_t</a> *node;
node = <a href='#mxmlNewTextf'>mxmlNewTextf</a>(node, 1, "%s/%s", node = mxmlNewTextf(node, 1, "%s/%s",
path, filename); path, filename);
</pre> </pre>
@ -376,7 +392,7 @@ use the following function call to create a new text node:</p>
<p>Mini-XML provides functions for managing indices of nodes. <p>Mini-XML provides functions for managing indices of nodes.
The current implementation provides the same functionality as The current implementation provides the same functionality as
the <a href='#mxmlFindElement'><tt>mxmlFindElement()</tt></a>. <a href='#mxmlFindElement'><tt>mxmlFindElement()</tt></a>.
The advantage of using an index is that searching and The advantage of using an index is that searching and
enumeration of elements is significantly faster. The only enumeration of elements is significantly faster. The only
disadvantage is that each index is a static snapshot of the XML disadvantage is that each index is a static snapshot of the XML
@ -392,10 +408,11 @@ href='#mxml_index_t'><tt>mxml_index_t</tt></a> structures. The
creates a new index:</p> creates a new index:</p>
<pre> <pre>
<a href='#mxml_node_t'>mxml_node_t</a> *tree; mxml_node_t *tree;
<a href='#mxml_index_t'>mxml_index_t</a> *ind; mxml_index_t *ind;
ind = <a href='#mxmlIndexNew'>mxmlIndexNew</a>(tree, "element", "attribute"); ind = mxmlIndexNew(tree, "element",
"attribute");
</pre> </pre>
<p>The first argument is the XML node tree to index. Normally this <p>The first argument is the XML node tree to index. Normally this
@ -424,8 +441,7 @@ function enumerates each of the nodes in the index and can be
used in a loop as follows:</p> used in a loop as follows:</p>
<pre> <pre>
<a href='#mxml_node_t'>mxml_node_t</a> *node; mxml_node_t *node;
<a href='#mxml_index_t'>mxml_index_t</a> *ind;
mxmlIndexReset(ind); mxmlIndexReset(ind);
@ -441,12 +457,13 @@ attribute value in the index. It can be used to find all
matching elements in an index, as follows:</p> matching elements in an index, as follows:</p>
<pre> <pre>
<a href='#mxml_node_t'>mxml_node_t</a> *node; mxml_node_t *node;
<a href='#mxml_index_t'>mxml_index_t</a> *ind;
mxmlIndexReset(ind); mxmlIndexReset(ind);
while ((node = mxmlIndexFind(ind, "element", "attr-value")) != NULL) while ((node = mxmlIndexFind(ind, "element",
"attr-value"))
!= NULL)
{ {
// do something with node // do something with node
} }
@ -458,14 +475,11 @@ to return all elements or attributes in the index. Passing
<tt>NULL</tt> for both the element name and attribute value <tt>NULL</tt> for both the element name and attribute value
is equivalent to calling <tt>mxmlIndexEnum</tt>.</p> is equivalent to calling <tt>mxmlIndexEnum</tt>.</p>
<!-- NEED 2in -->
<p>When you are done using the index, delete it using the <p>When you are done using the index, delete it using the
<a href='#mxmlIndexDelete()'><tt>mxmlIndexDelete()</tt></a> <a href='#mxmlIndexDelete()'><tt>mxmlIndexDelete()</tt></a>
function:</p> function:</p>
<pre> <pre>
<a href='#mxml_index_t'>mxml_index_t</a> *ind;
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
</pre> </pre>

@ -44,18 +44,20 @@ which determines which value you want to look at in the <a
href='#mxml_value_t'><tt>value</tt></a> union.</p> href='#mxml_value_t'><tt>value</tt></a> union.</p>
<p>New nodes can be created using the <a <p>New nodes can be created using the <a
href='#mxmlNewElement'><tt>mxmlNewElement()</tt></a>, href='#mxmlNewElement'><tt>mxmlNewElement()</tt></a>, <a
<a href='#mxmlNewInteger'><tt>mxmlNewInteger()</tt></a>, <a
href='#mxmlNewInteger'><tt>mxmlNewInteger()</tt></a>, href='#mxmlNewOpaque'><tt>mxmlNewOpaque()</tt></a>, <a
<a href='#mxmlNewReal'><tt>mxmlNewReal()</tt></a>, <a
href='#mxmlNewOpaque'><tt>mxmlNewOpaque()</tt></a>, href='#mxmlNewText'><tt>mxmlNewText()</tt></a> <a
<a href='#mxmlNewReal'><tt>mxmlNewReal()</tt></a>, href='#mxmlNewTextf'><tt>mxmlNewTextf()</tt></a> <a
and <a href='#mxmlNewXML'><tt>mxmlNewXML()</tt></a> functions. Only
href='#mxmlNewText'><tt>mxmlNewText()</tt></a> elements can have child nodes, and the top node must be an
functions. Only elements can have child nodes, and the top node element, usually <tt>&lt;?xml version="1.0"?&gt;</tt>.</p>
must be an element, usually "?xml".</p>
<p>Each node has a <tt>user_data</tt> member which allows you to
<p>Each node has pointers for the node above (<tt>parent</tt>), associate application-specific data with each node as needed.</p>
<p>Node also have pointers for the node above (<tt>parent</tt>),
below (<tt>child</tt>), to the left (<tt>prev</tt>), and to the 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 right (<tt>next</tt>) of the current node. If you have an XML
file like the following:</p> file like the following:</p>
@ -73,21 +75,20 @@ file like the following:</p>
&lt;/group&gt; &lt;/group&gt;
&lt;node&gt;val7&lt;/node&gt; &lt;node&gt;val7&lt;/node&gt;
&lt;node&gt;val8&lt;/node&gt; &lt;node&gt;val8&lt;/node&gt;
&lt;node&gt;val9&lt;/node&gt;
&lt;/data&gt; &lt;/data&gt;
</pre> </pre>
<p>the node tree returned by <tt>mxmlLoadFile()</tt> would look <p>the node tree for the file would look like the following in
like the following in memory:</p> memory:</p>
<pre> <pre>
?xml ?xml
| |
data data
| |
node - node - node - group - node - node - node node - node - node - group - node - node
| | | | | | | | | | | | |
val1 val2 val3 | val7 val8 val9 val1 val2 val3 | val7 val8
| |
node - node - node node - node - node
| | | | | |
@ -106,7 +107,80 @@ particular node or the entire tree:</p>
mxmlDelete(tree); mxmlDelete(tree);
</pre> </pre>
<!-- NEED 15 --> <!-- NEW PAGE -->
<h2>Creating XML Documents</h2>
<p>You can create and update XML documents in memory using the
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; */
xml = mxmlNewXML("1.0");
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");
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(data, "node");
mxmlNewText(node, 0, "val7");
node = mxmlNewElement(data, "node");
mxmlNewText(node, 0, "val8");
</pre>
<p>We start by creating the <tt>&lt;?xml version="1.0"?&gt;</tt>
node common to all XML files using the <a
href="#mxmlNewXML"><tt>mxmlNewXML</tt></a> function:</p>
<pre>
xml = mxmlNewXML("1.0");
</pre>
<p>We then create the <tt>&lt;data&gt;</tt> node used for this
document using the <a
href="#mxmlNewElement"><tt>mxmlNewElement</tt></a> function. The
first argument specifies the parent node (<tt>xml</tt>) while the
second specifies the element name (<tt>data</tt>):</p>
<pre>
data = mxmlNewElement(xml, "data");
</pre>
<p>Each <tt>&lt;node&gt;...&lt;/node&gt;</tt> in the file is
created using the <tt>mxmlNewElement</tt> and <a
href="#mxmlNewText"><tt>mxmlNewText</tt></a> functions. The first
argument of <tt>mxmlNewText</tt> specifies the parent node
(<tt>node</tt>). The second argument specifies whether whitespace
appears before 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");
</pre>
<p>The resulting in-memory XML document can then be saved or
processed just like one loaded from disk or a string.</p>
<!-- NEW PAGE -->
<h2>Loading XML</h2> <h2>Loading XML</h2>
<p>You load an XML file using the <a <p>You load an XML file using the <a
@ -115,10 +189,11 @@ function:</p>
<pre> <pre>
FILE *fp; FILE *fp;
<a href='#mxml_node_t'>mxml_node_t</a> *tree; mxml_node_t *tree;
fp = fopen("filename.xml", "r"); fp = fopen("filename.xml", "r");
tree = <a href='#mxmlLoadFile'>mxmlLoadFile</a>(NULL, fp, MXML_NO_CALLBACK); tree = mxmlLoadFile(NULL, fp,
MXML_TEXT_CALLBACK);
fclose(fp); fclose(fp);
</pre> </pre>
@ -133,14 +208,18 @@ opened by <tt>fopen()</tt> or <tt>popen()</tt>. You can also use
<tt>stdin</tt> if you are implementing an XML filter <tt>stdin</tt> if you are implementing an XML filter
program.</p> program.</p>
<p>The third argument specifies a callback function which <p>The third argument specifies a callback function which returns
returns the value type of the immediate children for a new the value type of the immediate children for a new element node:
element node: <tt>MXML_INTEGER</tt>, <tt>MXML_OPAQUE</tt>, <tt>MXML_CUSTOM</tt>, <tt>MXML_IGNORE</tt>,
<tt>MXML_REAL</tt>, or <tt>MXML_TEXT</tt>. Load callbacks are <tt>MXML_INTEGER</tt>, <tt>MXML_OPAQUE</tt>, <tt>MXML_REAL</tt>,
described in detail in <a href='#LOAD_CALLBACKS'>Chapter 3</a>. or <tt>MXML_TEXT</tt>. Load callbacks are described in detail in
The example code uses the <tt>MXML_NO_CALLBACK</tt> constant <a href='#LOAD_CALLBACKS'>Chapter 3</a>. The example code uses
which specifies that all data nodes in the document contain the <tt>MXML_TEXT_CALLBACK</tt> constant which specifies that all
whitespace-separated text values.</p> data nodes in the document contain whitespace-separated text
values. 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>
<p>The <a href='#mxmlLoadString'><tt>mxmlLoadString()</tt></a> <p>The <a href='#mxmlLoadString'><tt>mxmlLoadString()</tt></a>
function loads XML node trees from a string:</p> function loads XML node trees from a string:</p>
@ -148,11 +227,11 @@ function loads XML node trees from a string:</p>
<!-- NEED 10 --> <!-- NEED 10 -->
<pre> <pre>
char buffer[8192]; char buffer[8192];
<a href='#mxml_node_t'>mxml_node_t</a> *tree; mxml_node_t *tree;
... ...
tree = <a href='#mxmlLoadString'>mxmlLoadString</a>(NULL, buffer, tree = mxmlLoadString(NULL, buffer,
MXML_NO_CALLBACK); MXML_TEXT_CALLBACK);
</pre> </pre>
<p>The first and third arguments are the same as used for <p>The first and third arguments are the same as used for
@ -162,6 +241,7 @@ document including the <tt>?xml</tt> element if the parent node
is <tt>NULL</tt>.</p> is <tt>NULL</tt>.</p>
<!-- NEW PAGE -->
<h2>Saving XML</h2> <h2>Saving XML</h2>
<p>You save an XML file using the <a <p>You save an XML file using the <a
@ -169,10 +249,10 @@ href='#mxmlSaveFile'><tt>mxmlSaveFile()</tt></a> function:</p>
<pre> <pre>
FILE *fp; FILE *fp;
<a href='#mxml_node_t'>mxml_node_t</a> *tree; mxml_node_t *tree;
fp = fopen("filename.xml", "w"); fp = fopen("filename.xml", "w");
<a href='#mxmlSaveFile'>mxmlSaveFile</a>(tree, fp, MXML_NO_CALLBACK); mxmlSaveFile(tree, fp, MXML_NO_CALLBACK);
fclose(fp); fclose(fp);
</pre> </pre>
@ -186,8 +266,8 @@ by <tt>fopen()</tt> or <tt>popen()</tt>. You can also use
program.</p> program.</p>
<p>The third argument is the whitespace callback to use when <p>The third argument is the whitespace callback to use when
saving the file. Whitespace callbacks are covered in detail in saving the file. Whitespace callbacks are covered in detail in <a
<a href='SAVE_CALLBACKS'>Chapter 3</a>. The example code above href='SAVE_CALLBACKS'>Chapter 3</a>. The previous example code
uses the <tt>MXML_NO_CALLBACK</tt> constant to specify that no uses the <tt>MXML_NO_CALLBACK</tt> constant to specify that no
special whitespace handling is required.</p> special whitespace handling is required.</p>
@ -199,14 +279,14 @@ functions save XML node trees to strings:</p>
<pre> <pre>
char buffer[8192]; char buffer[8192];
char *ptr; char *ptr;
<a href='#mxml_node_t'>mxml_node_t</a> *tree; mxml_node_t *tree;
... ...
<a href='#mxmlSaveString'>mxmlSaveString</a>(tree, buffer, sizeof(buffer), mxmlSaveString(tree, buffer, sizeof(buffer),
MXML_NO_CALLBACK); MXML_NO_CALLBACK);
... ...
ptr = <a href='#mxmlSaveAllocString'>mxmlSaveAllocString</a>(tree, MXML_NO_CALLBACK); ptr = mxmlSaveAllocString(tree, MXML_NO_CALLBACK);
</pre> </pre>
<p>The first and last arguments are the same as used for <p>The first and last arguments are the same as used for
@ -216,8 +296,25 @@ a fixed-size buffer, while <tt>mxmlSaveAllocString()</tt>
returns a string buffer that was allocated using returns a string buffer that was allocated using
<tt>malloc()</tt>.</p> <tt>malloc()</tt>.</p>
<h3>Controlling Line Wrapping</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>
<h3>Finding and Iterating Nodes</h3>
<!-- NEW PAGE-->
<h2>Finding and Iterating Nodes</h2>
<p>The <a <p>The <a
href='#mxmlWalkPrev'><tt>mxmlWalkPrev()</tt></a> href='#mxmlWalkPrev'><tt>mxmlWalkPrev()</tt></a>
@ -226,11 +323,13 @@ href='#mxmlWalkNext'><tt>mxmlWalkNext()</tt></a>functions
can be used to iterate through the XML node tree:</p> can be used to iterate through the XML node tree:</p>
<pre> <pre>
<a href='#mxml_node_t'>mxml_node_t</a> *node; mxml_node_t *node;
node = <a href='#mxmlWalkPrev'>mxmlWalkPrev</a>(current, tree, MXML_DESCEND); node = mxmlWalkPrev(current, tree,
MXML_DESCEND);
node = <a href='#mxmlWalkNext'>mxmlWalkNext</a>(current, tree, MXML_DESCEND); node = mxmlWalkNext(current, tree,
MXML_DESCEND);
</pre> </pre>
<p>In addition, you can find a named element/node using the <a <p>In addition, you can find a named element/node using the <a
@ -238,9 +337,9 @@ href='#mxmlFindElement'><tt>mxmlFindElement()</tt></a>
function:</p> function:</p>
<pre> <pre>
<a href='#mxml_node_t'>mxml_node_t</a> *node; mxml_node_t *node;
node = <a href='#mxmlFindElement'>mxmlFindElement</a>(tree, tree, "name", node = mxmlFindElement(tree, tree, "name",
"attr", "value", "attr", "value",
MXML_DESCEND); MXML_DESCEND);
</pre> </pre>
@ -249,34 +348,43 @@ function:</p>
arguments can be passed as <tt>NULL</tt> to act as wildcards, arguments can be passed as <tt>NULL</tt> to act as wildcards,
e.g.:</p> e.g.:</p>
<!-- NEED 4 -->
<pre> <pre>
/* Find the first "a" element */ /* Find the first "a" element */
node = <a href='#mxmlFindElement'>mxmlFindElement</a>(tree, tree, "a", node = mxmlFindElement(tree, tree, "a",
NULL, NULL, NULL, NULL,
MXML_DESCEND); MXML_DESCEND);
</pre>
<!-- NEED 5 -->
<pre>
/* Find the first "a" element with "href" /* Find the first "a" element with "href"
attribute */ attribute */
node = <a href='#mxmlFindElement'>mxmlFindElement</a>(tree, tree, "a", node = mxmlFindElement(tree, tree, "a",
"href", NULL, "href", NULL,
MXML_DESCEND); MXML_DESCEND);
</pre>
<!-- NEED 6 -->
<pre>
/* Find the first "a" element with "href" /* Find the first "a" element with "href"
to a URL */ to a URL */
node = <a href='#mxmlFindElement'>mxmlFindElement</a>(tree, tree, "a", node = mxmlFindElement(tree, tree, "a",
"href", "href",
"http://www.easysw.com/", "http://www.easysw.com/",
MXML_DESCEND); MXML_DESCEND);
</pre>
<!-- NEED 5 -->
<pre>
/* Find the first element with a "src" /* Find the first element with a "src"
attribute */ attribute */
node = <a href='#mxmlFindElement'>mxmlFindElement</a>(tree, tree, NULL, node = mxmlFindElement(tree, tree, NULL,
"src", NULL, "src", NULL,
MXML_DESCEND); MXML_DESCEND);
</pre>
<!-- NEED 5 -->
<pre>
/* Find the first element with a "src" /* Find the first element with a "src"
= "foo.jpg" */ = "foo.jpg" */
node = <a href='#mxmlFindElement'>mxmlFindElement</a>(tree, tree, NULL, node = mxmlFindElement(tree, tree, NULL,
"src", "foo.jpg", "src", "foo.jpg",
MXML_DESCEND); MXML_DESCEND);
</pre> </pre>
@ -284,13 +392,15 @@ e.g.:</p>
<p>You can also iterate with the same function:</p> <p>You can also iterate with the same function:</p>
<pre> <pre>
<a href='#mxml_node_t'>mxml_node_t</a> *node; mxml_node_t *node;
for (node = <a href='#mxmlFindElement'>mxmlFindElement</a>(tree, tree, "name", for (node = mxmlFindElement(tree, tree,
"name",
NULL, NULL, NULL, NULL,
MXML_DESCEND); MXML_DESCEND);
node != NULL; node != NULL;
node = <a href='#mxmlFindElement'>mxmlFindElement</a>(node, tree, "name", node = mxmlFindElement(node, tree,
"name",
NULL, NULL, NULL, NULL,
MXML_DESCEND)) MXML_DESCEND))
{ {
@ -298,6 +408,7 @@ e.g.:</p>
} }
</pre> </pre>
<!-- NEED 10 -->
<p>The <tt>MXML_DESCEND</tt> argument can actually be one of <p>The <tt>MXML_DESCEND</tt> argument can actually be one of
three constants:</p> three constants:</p>
@ -309,7 +420,7 @@ three constants:</p>
node or top-of-tree is reached. The previous node from node or top-of-tree is reached. The previous node from
"group" would be the "node" element to the left, while "group" would be the "node" element to the left, while
the next node from "group" would be the "node" element the next node from "group" would be the "node" element
to the right.</li> to the right.<br><br></li>
<li><tt>MXML_DESCEND_FIRST</tt> means that it is OK to <li><tt>MXML_DESCEND_FIRST</tt> means that it is OK to
descend to the first child of a node, but not to descend descend to the first child of a node, but not to descend
@ -319,40 +430,19 @@ three constants:</p>
in the example above. This mode is only applicable to in the example above. This mode is only applicable to
the search function; the walk functions treat this as the search function; the walk functions treat this as
<tt>MXML_DESCEND</tt> since every call is a first <tt>MXML_DESCEND</tt> since every call is a first
time.</li> time.<br><br></li>
<li><tt>MXML_DESCEND</tt> means to keep descending until <li><tt>MXML_DESCEND</tt> means to keep descending until
you hit the bottom of the tree. The previous node from you hit the bottom of the tree. The previous node from
"group" would be the "val3" node and the next node would "group" would be the "val3" node and the next node would
be the first node element under "group". If you were to be the first node element under "group". If you were to
walk from the root node "?xml" to the end of the walk from the root node "?xml" to the end of the tree
tree with <tt>mxmlWalkNext()</tt>, the order would be: with <tt>mxmlWalkNext()</tt>, the order would be:
<pre> <p><tt>?xml data node val1 node val2 node val3 group node
?xml val4 node val5 node val6 node val7 node val8</tt></p>
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 <p>If you started at "val8" and walked using
<tt>mxmlWalkPrev()</tt>, the order would be reversed, <tt>mxmlWalkPrev()</tt>, the order would be reversed,
ending at "?xml".</p></li> ending at "?xml".</p></li>

@ -71,6 +71,7 @@
<li><a href='#mxmlNewReal'><tt>mxmlNewReal()</tt></a> </li> <li><a href='#mxmlNewReal'><tt>mxmlNewReal()</tt></a> </li>
<li><a href='#mxmlNewText'><tt>mxmlNewText()</tt></a> </li> <li><a href='#mxmlNewText'><tt>mxmlNewText()</tt></a> </li>
<li><a href='#mxmlNewTextf'><tt>mxmlNewTextf()</tt></a> </li> <li><a href='#mxmlNewTextf'><tt>mxmlNewTextf()</tt></a> </li>
<li><a href='#mxmlNewXML'><tt>mxmlNewXML()</tt></a> <span class='info'>&nbsp;Mini-XML 2.3&nbsp;</span></li>
<li><a href='#mxmlRelease'><tt>mxmlRelease()</tt></a> <span class='info'>&nbsp;Mini-XML 2.3&nbsp;</span></li> <li><a href='#mxmlRelease'><tt>mxmlRelease()</tt></a> <span class='info'>&nbsp;Mini-XML 2.3&nbsp;</span></li>
<li><a href='#mxmlRemove'><tt>mxmlRemove()</tt></a> </li> <li><a href='#mxmlRemove'><tt>mxmlRemove()</tt></a> </li>
<li><a href='#mxmlRetain'><tt>mxmlRetain()</tt></a> <span class='info'>&nbsp;Mini-XML 2.3&nbsp;</span></li> <li><a href='#mxmlRetain'><tt>mxmlRetain()</tt></a> <span class='info'>&nbsp;Mini-XML 2.3&nbsp;</span></li>
@ -745,6 +746,29 @@ mxmlNewTextf(
<h4>Returns</h4> <h4>Returns</h4>
<p>New node</p> <p>New node</p>
<!-- NEW PAGE --> <!-- NEW PAGE -->
<h3 class='title'><span class='info'>&nbsp;Mini-XML 2.3&nbsp;</span><a name='mxmlNewXML'>mxmlNewXML()</a></h3>
<h4>Description</h4>
<p>Create a new XML document tree.
The &quot;version&quot; argument specifies the version number to put in the
?xml element node. If NULL, version 1.0 is assumed.
</p>
<h4>Syntax</h4>
<pre>
<a href='#mxml_node_t'>mxml_node_t</a> *
mxmlNewXML(
const char * version);
</pre>
<h4>Arguments</h4>
<div class='table'><table align='center' border='1' width='80%' cellpadding='5' cellspacing='0'>
<thead><tr><th>Name</th><th>Description</th></tr></thead>
<tbody>
<tr><td><tt>version</tt></td><td>Version number to use</td></tr>
</tbody></table></div>
<h4>Returns</h4>
<p>New ?xml node</p>
<!-- NEW PAGE -->
<h3 class='title'><span class='info'>&nbsp;Mini-XML 2.3&nbsp;</span><a name='mxmlRelease'>mxmlRelease()</a></h3> <h3 class='title'><span class='info'>&nbsp;Mini-XML 2.3&nbsp;</span><a name='mxmlRelease'>mxmlRelease()</a></h3>
<h4>Description</h4> <h4>Description</h4>
<p>Release a node. <p>Release a node.

@ -8,12 +8,14 @@
<ul> <ul>
<li>Added two exceptions to the LGPL to support static <li>Added two exceptions to the LGPL to support static
linking of applications against Mini-XML.</li> linking of applications against Mini-XML</li>
<li>Added mxmlElementSetAttrf() function (STR #43)</li> <li>Added a mxmlNewXML() function</li>
<li>Added snprintf() emulation function for test program <li>Added a mxmlElementSetAttrf() function (STR #43)</li>
(STR #32)</li>
<li>Added a snprintf() emulation function for the test
program (STR #32)</li>
<li>Added the _CRT_SECURE_NO_DEPRECATE definition when <li>Added the _CRT_SECURE_NO_DEPRECATE definition when
building on VC++ 2005 (STR #36)</li> building on VC++ 2005 (STR #36)</li>
@ -21,52 +23,52 @@
<li>mxmlLoad*() did not detect missing > characters in <li>mxmlLoad*() did not detect missing > characters in
elements (STR #41)</li> elements (STR #41)</li>
<li>mxmlLoad*() did not detect missing close tags at the end <li>mxmlLoad*() did not detect missing close tags at the
of an XML document (STR #45)</li> end of an XML document (STR #45)</li>
<li>Added user_data and ref_count members to mxml_node_t <li>Added user_data and ref_count members to mxml_node_t
structure.</li> structure</li>
<li>Added mxmlReleaseNode() and mxmlRetainNode() APIs for <li>Added mxmlReleaseNode() and mxmlRetainNode() APIs for
reference-counted nodes.</li> reference-counted nodes</li>
<li>Added mxmlSetWrapMargin() to control the wrapping of XML <li>Added mxmlSetWrapMargin() to control the wrapping of
output.</li> XML output</li>
<li>Added conditional check for EINTR error code for <li>Added conditional check for EINTR error code for
certain Windows compilers that do not define it (STR certain Windows compilers that do not define it (STR
#33)</li> #33)</li>
<li>The mxmldoc program now generates correct HTML 4.0 <li>The mxmldoc program now generates correct HTML 4.0
output (previously it generated invalid XHTML...)</li> output - previously it generated invalid XHTML</li>
<li>The mxmldoc program now supports "@deprecated@, <li>The mxmldoc program now supports "@deprecated@,
"@private@", and "@since version@" comments.</li> "@private@", and "@since version@" comments</li>
<li>Fixed function and enumeraion type bugs in <li>Fixed function and enumeration type bugs in
mxmldoc.</li> mxmldoc</li>
<li>Fixed XML schema for mxmldoc.</li> <li>Fixed the XML schema for mxmldoc</li>
<li>The mxmldoc program now supports --intro, --section, <li>The mxmldoc program now supports --intro, --section,
and --title options.</li> and --title options</li>
<li>The mxmlLoad*() functions could leak a node on an <li>The mxmlLoad*() functions could leak a node on an
error (STR #27)</li> error (STR #27)</li>
<li>The mxml_vsnprintf() function could get in an infinite <li>The mxml_vsnprintf() function could get in an
loop on a buffer overflow (STR #25)</li> infinite loop on a buffer overflow (STR #25)</li>
<li>Added new mxmlNewCDATA() and mxmlSetCDATA() functions <li>Added new mxmlNewCDATA() and mxmlSetCDATA() functions
to create and set CDATA nodes, which are really just to create and set CDATA nodes, which are really just
special element nodes.</li> special element nodes</li>
<li>Added new MXML_IGNORE type and MXML_IGNORE_CB <li>Added new MXML_IGNORE type and MXML_IGNORE_CB
callback to ignore non-element nodes (i.e. callback to ignore non-element nodes, e.g.
whitespace)</li> whitespace</li>
<li>mxmlLoad*() did not treat custom data as opaque, so <li>mxmlLoad*() did not treat custom data as opaque, so
whitespace characters would be lost.</li> whitespace characters would be lost</li>
</ul> </ul>

@ -27,6 +27,7 @@
* mxmlNewReal() - Create a new real number node. * mxmlNewReal() - Create a new real number node.
* mxmlNewText() - Create a new text fragment node. * mxmlNewText() - Create a new text fragment node.
* mxmlNewTextf() - Create a new formatted text fragment node. * mxmlNewTextf() - Create a new formatted text fragment node.
* mxmlNewXML() - Create a new XML document tree.
* mxmlRelease() - Release a node. * mxmlRelease() - Release a node.
* mxmlRemove() - Remove a node from its parent. * mxmlRemove() - Remove a node from its parent.
* mxmlRetain() - Retain a node. * mxmlRetain() - Retain a node.
@ -655,6 +656,28 @@ mxmlRemove(mxml_node_t *node) /* I - Node to remove */
} }
/*
* 'mxmlNewXML()' - Create a new XML document tree.
*
* The "version" argument specifies the version number to put in the
* ?xml element node. If NULL, version 1.0 is assumed.
*
* @since Mini-XML 2.3@
*/
mxml_node_t * /* O - New ?xml node */
mxmlNewXML(const char *version) /* I - Version number to use */
{
char element[1024]; /* Element text */
snprintf(element, sizeof(element), "?xml version=\"%s\"?",
version ? version : "1.0");
return (mxmlNewElement(NULL, element));
}
/* /*
* 'mxmlRelease()' - Release a node. * 'mxmlRelease()' - Release a node.
* *

@ -207,6 +207,7 @@ extern mxml_node_t *mxmlNewTextf(mxml_node_t *parent, int whitespace,
__attribute__ ((__format__ (__printf__, 3, 4))) __attribute__ ((__format__ (__printf__, 3, 4)))
# endif /* __GNUC__ */ # endif /* __GNUC__ */
; ;
extern mxml_node_t *mxmlNewXML(const char *version);
extern int mxmlRelease(mxml_node_t *node); extern int mxmlRelease(mxml_node_t *node);
extern void mxmlRemove(mxml_node_t *node); extern void mxmlRemove(mxml_node_t *node);
extern int mxmlRetain(mxml_node_t *node); extern int mxmlRetain(mxml_node_t *node);

@ -512,6 +512,22 @@ string must be nul-terminated and is formatted into the new node.</description>
<type /> <description>Additional args as needed</description> <type /> <description>Additional args as needed</description>
</argument> </argument>
</function> </function>
<function name="mxmlNewXML">
<returnvalue>
<type>mxml_node_t *</type>
<description>New ?xml node</description>
</returnvalue>
<description>Create a new XML document tree.
The &quot;version&quot; argument specifies the version number to put in the
?xml element node. If NULL, version 1.0 is assumed.
@since Mini-XML 2.3@</description>
<argument name="version" direction="I">
<type>const char *</type>
<description>Version number to use</description>
</argument>
</function>
<function name="mxmlRelease"> <function name="mxmlRelease">
<returnvalue> <returnvalue>
<type>int</type> <type>int</type>

@ -645,7 +645,7 @@ new_documentation(mxml_node_t **mxmldoc)/* O - mxmldoc node */
* Create an empty XML documentation file... * Create an empty XML documentation file...
*/ */
doc = mxmlNewElement(NULL, "?xml version=\"1.0\"?"); doc = mxmlNewXML(NULL);
*mxmldoc = mxmlNewElement(doc, "mxmldoc"); *mxmldoc = mxmlNewElement(doc, "mxmldoc");

@ -613,7 +613,7 @@ whitespace_cb(mxml_node_t *node, /* I - Element node */
else if (where == MXML_WS_AFTER_CLOSE) else if (where == MXML_WS_AFTER_CLOSE)
return ("\n"); return ("\n");
} }
else if (!strcmp(name, "?xml")) else if (!strncmp(name, "?xml", 4))
{ {
return (NULL); return (NULL);
} }

Loading…
Cancel
Save