Add mxmlLoadIO/mxmlSaveIO functions, merge everything under the new roof

(Issue #98)
master
Michael R Sweet 2 months ago
parent e54574aca7
commit 4e92848ae2
No known key found for this signature in database
GPG Key ID: BE67C75EC81F3244
  1. 2
      CHANGES.md
  2. 164
      doc/body.md
  3. 276
      doc/mxml.3
  4. BIN
      doc/mxml.epub
  5. 486
      doc/mxml.html
  6. 8
      mxml-attr.c
  7. 20
      mxml-entity.c
  8. 2304
      mxml-file.c
  9. 34
      mxml-get.c
  10. 8
      mxml-index.c
  11. 8
      mxml-node.c
  12. 56
      mxml-private.c
  13. 2
      mxml-private.h
  14. 84
      mxml-set.c
  15. 91
      mxml.h
  16. 213
      testmxml.c

@ -3,6 +3,8 @@
- Now require C99 support.
- Now install as "libmxml4" to support installing both Mini-XML 3.x and 4.x at
the same time (use `--disable-libmxml4-prefix` configure option to disable)
- Added `mxmlLoadIO` and `mxmlSaveIO` functions to load and save XML via
callbacks (Issue #98)
- Added new `MXML_TYPE_CDATA`, `MXML_TYPE_COMMENT`, `MXML_TYPE_DECLARATION`, and
`MXML_TYPE_DIRECTIVE` node types (Issue #250)
- Renamed `mxml_type_t` enumerations to `MXML_TYPE_xxx` (Issue #251)

@ -99,47 +99,55 @@ You load an XML file using the `mxmlLoadFile` function:
```c
mxml_node_t *
mxmlLoadFile(mxml_node_t *top, FILE *fp,
mxml_type_t (*cb)(mxml_node_t *));
mxml_load_cb_t load_cb, void *load_cbdata,
mxml_sax_cb_t sax_cb, void *sax_cbdata);
```
The `cb` argument specifies a function that assigns child (value) node types for
each element in the document. The callback can be a function you provide or one
of the standard functions provided with Mini-XML. For example, to load the XML
file "filename.xml" containing text strings you can use the
`MXML_OPAQUE_CALLBACK` function:
The `load_cb` argument specifies a function that assigns child (value) node
types for each element in the document. The default callback (`NULL`) supports
passing a pointer to an `mxml_type_t` variable containing the type of value
nodes. For example, to load the XML file "filename.xml" containing literal
strings you can use:
```c
FILE *fp;
mxml_node_t *tree;
mxml_type_t type = MXML_TYPE_OPAQUE;
fp = fopen("filename.xml", "r");
tree = mxmlLoadFile(NULL, fp, MXML_OPAQUE_CALLBACK);
tree = mxmlLoadFile(/*top*/NULL, fp, /*load_cb*/NULL, &type,
/*sax_cb*/NULL, /*sax_cbdata*/NULL);
fclose(fp);
```
Mini-XML also provides functions to load from a file descriptor or string:
Mini-XML also provides functions to load from a named file, a file descriptor,
or string:
```c
mxml_node_t *
mxmlLoadFd(mxml_node_t *top, int fd,
mxml_type_t (*cb)(mxml_node_t *));
mxml_load_cb_t load_cb, void *load_cbdata,
mxml_sax_cb_t sax_cb, void *sax_cbdata);
mxml_node_t *
mxmlLoadFilename(mxml_node_t *top, const char *filename,
mxml_load_cb_t load_cb, void *load_cbdata,
mxml_sax_cb_t sax_cb, void *sax_cbdata);
mxml_node_t *
mxmlLoadString(mxml_node_t *top, const char *s,
mxml_type_t (*cb)(mxml_node_t *));
mxml_load_cb_t load_cb, void *load_cbdata,
mxml_sax_cb_t sax_cb, void *sax_cbdata);
```
### Load Callbacks
The last argument to the `mxmlLoad` functions is a callback function which is
used to determine the value type of each data node in an XML document. Mini-XML
defines several standard callbacks for simple XML data files:
- `MXML_INTEGER_CALLBACK`: All data nodes contain whitespace-separated integers.
- `MXML_OPAQUE_CALLBACK`: All data nodes contain opaque strings with whitespace preserved.
- `MXML_REAL_CALLBACK` - All data nodes contain whitespace-separated floating-point numbers.
- `MXML_TEXT_CALLBACK` - All data nodes contain whitespace-separated strings.
The `load_xxx` arguments to the `mxmlLoad` functions are a callback function and
a data pointer which are used to determine the value type of each data node in
an XML document. The default (`NULL`) callback expects the `load_cbdata`
argument to be a pointer to a `mxml_type_t` variable - if `NULL` it returns the
`MXML_TYPE_TEXT` type.
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
@ -154,7 +162,7 @@ element name to determine the value type for its child nodes:
```c
mxml_type_t
type_cb(mxml_node_t *node)
type_cb(void *cbdata, mxml_node_t *node)
{
const char *type;
@ -186,7 +194,9 @@ FILE *fp;
mxml_node_t *tree;
fp = fopen("filename.xml", "r");
tree = mxmlLoadFile(NULL, fp, type_cb);
tree = mxmlLoadFile(/*top*/NULL, fp,
type_cb, /*load_cbdata*/NULL,
/*sax_cb*/NULL, /*sax_cbata*/NULL);
fclose(fp);
```
@ -846,7 +856,7 @@ for (node = xml;
The nodes will be returned in the following order:
```c
```
<?xml version="1.0" encoding="utf-8"?>
<data>
<node>
@ -952,17 +962,13 @@ mxmlIndexDelete(mxml_index_t *ind);
Custom Data Types
=================
Mini-XML supports
-------------------- data types via per-thread load and save callbacks.
Mini-XML supports custom data types via per-thread load and save callbacks.
Only a single set of callbacks can be active at any time for the current thread,
however your callbacks can store additional information in order to support
multiple
-------------------- data types as needed. The `MXML_TYPE_CUSTOM` node type
identifies
-------------------- data nodes.
multiple custom data types as needed. The `MXML_TYPE_CUSTOM` node type
identifies custom data nodes.
The `mxmlGetCustom` function retrieves the
-------------------- value pointer for a node.
The `mxmlGetCustom` function retrieves the custom value pointer for a node.
```c
const void *
@ -970,40 +976,31 @@ mxmlGetCustom(mxml_node_t *node);
```
Custom \(`MXML_TYPE_CUSTOM`) nodes are created using the `mxmlNewCustom`
function or using a
-------------------- per-thread load callbacks specified using the
function or using a custom per-thread load callbacks specified using the
`mxmlSetCustomHandlers` function:
```c
typedef void (*mxml_
--------------------_destroy_cb_t)(void *);
typedef bool (*mxml_
--------------------_load_cb_t)(mxml_node_t *, const char *);
typedef char *(*mxml_
--------------------_save_cb_t)(mxml_node_t *);
typedef void (*mxml_custom_destroy_cb_t)(void *);
typedef bool (*mxml_custom_load_cb_t)(mxml_node_t *, const char *);
typedef char *(*mxml_custom_save_cb_t)(mxml_node_t *);
mxml_node_t *
mxmlNewCustom(mxml_node_t *parent, void *data,
mxml_
--------------------_destroy_cb_t destroy);
mxml_custom_destroy_cb_t destroy);
int
mxmlSetCustom(mxml_node_t *node, void *data,
mxml_
--------------------_destroy_cb_t destroy);
mxml_custom_destroy_cb_t destroy);
void
mxmlSetCustomHandlers(mxml_
--------------------_load_cb_t load,
mxml_
--------------------_save_cb_t save);
mxmlSetCustomHandlers(mxml_custom_load_cb_t load,
mxml_custom_save_cb_t save);
```
The load callback receives a pointer to the current data node and a string of
opaque character data from the XML source with character entities converted to
the corresponding UTF-8 characters. For example, if we wanted to support a
-------------------- date/time type whose value is encoded as "yyyy-mm-ddThh:mm:ssZ" (ISO
custom date/time type whose value is encoded as "yyyy-mm-ddThh:mm:ssZ" (ISO
format), the load callback would look like the following:
```c
@ -1019,8 +1016,7 @@ typedef struct
} iso_date_time_t;
bool
load_
--------------------(mxml_node_t *node, const char *data)
load_custom(mxml_node_t *node, const char *data)
{
iso_date_time_t *dt;
struct tm tmdata;
@ -1082,8 +1078,7 @@ load_
dt->unix = gmtime(&tmdata);
/*
* Assign
-------------------- node data and destroy (free) function
* Assign custom node data and destroy (free) function
* pointers...
*/
@ -1098,24 +1093,19 @@ load_
```
The function itself can return `true` on success or `false` if it is unable to
decode the
-------------------- data or the data contains an error. Custom data nodes contain
a `void` pointer to the allocated
-------------------- data for the node and a pointer to a
destructor function which will free the
-------------------- data when the node is deleted.
decode the custom data or the data contains an error. Custom data nodes contain
a `void` pointer to the allocated custom data for the node and a pointer to a
destructor function which will free the custom data when the node is deleted.
In this example, we use the standard `free` function since everything is
contained in a single calloc'd block.
The save callback receives the node pointer and returns an allocated string
containing the
-------------------- data value. The following save callback could be used for
containing the custom data value. The following save callback could be used for
our ISO date/time type:
```c
char *
save_
--------------------(mxml_node_t *node)
save_custom(mxml_node_t *node)
{
char data[255];
iso_date_time_t *dt;
@ -1135,9 +1125,7 @@ save_
You register the callback functions using the `mxmlSetCustomHandlers` function:
```c
mxmlSetCustomHandlers(load_
--------------------, save_
--------------------);
mxmlSetCustomHandlers(load_custom, save_custom);
```
@ -1150,35 +1138,15 @@ allowing you to process XML documents of any size, the Mini-XML implementation
also allows you to retain portions of the document in memory for later
processing.
The `mxmlSAXLoadFd`, `mxmlSAXLoadFile`, and `mxmlSAXLoadString` functions
provide the SAX loading APIs:
```c
mxml_node_t *
mxmlSAXLoadFd(mxml_node_t *top, int fd,
mxml_type_t (*cb)(mxml_node_t *),
mxml_sax_cb_t sax, void *sax_data);
mxml_node_t *
mxmlSAXLoadFile(mxml_node_t *top, FILE *fp,
mxml_type_t (*cb)(mxml_node_t *),
mxml_sax_cb_t sax, void *sax_data);
mxml_node_t *
mxmlSAXLoadString(mxml_node_t *top, const char *s,
mxml_type_t (*cb)(mxml_node_t *),
mxml_sax_cb_t sax, void *sax_data);
```
Each function works like the corresponding `mxmlLoad` function but uses a
callback to process each node as it is read. The callback function receives the
node, an event code, and a user data pointer you supply and returns `true` to
continue processing or `false` to stop:
The `mxmlLoadFd`, `mxmlLoadFile`, `mxmlLoadFilename`, `mxmlLoadIO`, and
`mxmlLoadString` functions support a SAX callback and associated data. The
callback function receives the data pointer you supplied, the node, and an event
code and returns `true` to continue processing or `false` to stop:
```c
bool
sax_cb(mxml_node_t *node, mxml_sax_event_t event,
void *data)
sax_cb(void *cbdata, mxml_node_t *node,
mxml_sax_event_t event)
{
... do something ...
@ -1204,8 +1172,7 @@ retain all nodes, effectively simulating a normal in-memory load:
```c
bool
sax_cb(mxml_node_t *node, mxml_sax_event_t event,
void *data)
sax_cb(void *cbdata, mxml_node_t *node, mxml_sax_event_t event)
{
if (event != MXML_SAX_ELEMENT_CLOSE)
mxmlRetain(node);
@ -1222,8 +1189,8 @@ directives like `<?xml ... ?>` and declarations like `<!DOCTYPE ... >`:
```c
bool
sax_cb(mxml_node_t *node, mxml_sax_event_t event,
void *data)
sax_cb(void *cbdata, mxml_node_t *node,
mxml_sax_event_t event)
{
if (event == MXML_SAX_ELEMENT_OPEN)
{
@ -1267,15 +1234,16 @@ sax_cb(mxml_node_t *node, mxml_sax_event_t event,
```
The resulting skeleton document tree can then be searched just like one loaded
using the `mxmlLoad` functions. For example, a filter that reads an XHTML
without the SAX callback function. For example, a filter that reads an XHTML
document from stdin and then shows the title and headings in the document would
look like:
```c
mxml_node_t *doc, *title, *body, *heading;
doc = mxmlSAXLoadFd(NULL, 0, MXML_TEXT_CALLBACK, sax_cb,
NULL);
doc = mxmlLoadFd(/*top*/NULL, /*fd*/0,
/*load_cb*/NULL, /*load_cbdata*/NULL,
sax_cb, /*sax_cbdata*/NULL);
title = mxmlFindElement(doc, doc, "title", NULL, NULL,
MXML_DESCEND);
@ -1329,6 +1297,8 @@ The following incompatible API changes were made in Mini-XML v4.0:
- SAX events are now named `MXML_SAX_EVENT_foo` instead of `MXML_SAX_foo`.
- SAX callbacks now return a boolean value.
- The `mxmlSAXLoadXxx` functions have been removed in favor of passing the SAX
callback function and data pointers to the `mxmlLoadXxx` functions.
- Node types are now named `MXML_TYPE_foo` instead of `MXML_foo`.
- Functions that returned `0` on success and `-1` on error now return `true` on
success and `false` on error.

@ -1,4 +1,4 @@
.TH mxml 3 "Mini-XML API" "2024-03-04" "Mini-XML API"
.TH mxml 3 "Mini-XML API" "2024-03-06" "Mini-XML API"
.SH NAME
mxml \- Mini-XML API
.SH INCLUDE FILE
@ -259,6 +259,24 @@ Real value
MXML_TYPE_TEXT
.br
Text fragment
.SS mxml_ws_e
Whitespace periods
.TP 5
MXML_WS_AFTER_CLOSE
.br
Callback for after close tag
.TP 5
MXML_WS_AFTER_OPEN
.br
Callback for after open tag
.TP 5
MXML_WS_BEFORE_CLOSE
.br
Callback for before close tag
.TP 5
MXML_WS_BEFORE_OPEN
.br
Callback for before open tag
.SH FUNCTIONS
.SS mxmlAdd
Add a node to a tree.
@ -370,16 +388,6 @@ bool mxmlEntityAddCallback (
mxml_entity_cb_t cb
);
.fi
.SS mxmlEntityGetName
Get the name that corresponds to the character value.
.PP
.nf
const char * mxmlEntityGetName (
int val
);
.fi
.PP
If val does not need to be represented by a named entity, \fBNULL\fR is returned.
.SS mxmlEntityGetValue
Get the character corresponding to a named entity.
.PP
@ -667,7 +675,7 @@ to calling \fImxmlIndexEnum\fR.
Get the number of nodes in an index.
.PP
.nf
int mxmlIndexGetCount (
size_t mxmlIndexGetCount (
mxml_index_t *ind
);
.fi
@ -706,7 +714,10 @@ Load a file descriptor into an XML node tree.
mxml_node_t * mxmlLoadFd (
mxml_node_t *top,
int fd,
mxml_load_cb_t cb
mxml_load_cb_t load_cb,
void *load_cbdata,
mxml_sax_cb_t sax_cb,
void *sax_cbdata
);
.fi
.PP
@ -716,8 +727,8 @@ single parent node like
.URL ?xml ?xml
for the entire file. The callback
function returns the value type that should be used for child nodes.
The constants \fBMXML_INTEGER_CALLBACK\fR, \fBMXML_TYPE_OPAQUE_CALLBACK\fR,
\fBMXML_REAL_CALLBACK\fR, and \fBMXML_TYPE_TEXT_CALLBACK\fR are defined for
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
@ -732,7 +743,10 @@ Load a file into an XML node tree.
mxml_node_t * mxmlLoadFile (
mxml_node_t *top,
FILE *fp,
mxml_load_cb_t cb
mxml_load_cb_t load_cb,
void *load_cbdata,
mxml_sax_cb_t sax_cb,
void *sax_cbdata
);
.fi
.PP
@ -742,8 +756,67 @@ single parent node like
.URL ?xml ?xml
for the entire file. The callback
function returns the value type that should be used for child nodes.
The constants \fBMXML_INTEGER_CALLBACK\fR, \fBMXML_TYPE_OPAQUE_CALLBACK\fR,
\fBMXML_REAL_CALLBACK\fR, and \fBMXML_TYPE_TEXT_CALLBACK\fR are defined for
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 mxmlLoadFilename
Load a file into an XML node tree.
.PP
.nf
mxml_node_t * mxmlLoadFilename (
mxml_node_t *top,
const char *filename,
mxml_load_cb_t load_cb,
void *load_cbdata,
mxml_sax_cb_t sax_cb,
void *sax_cbdata
);
.fi
.PP
The nodes in the specified file are added to the specified top node.
If no top node is provided, the XML file MUST be well-formed with a
single parent node like
.URL ?xml ?xml
for the entire file. The callback
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 mxmlLoadIO
Load an XML node tree using a read callback.
.PP
.nf
mxml_node_t * mxmlLoadIO (
mxml_node_t *top,
mxml_read_cb_t read_cb,
void *read_cbdata,
mxml_load_cb_t load_cb,
void *load_cbdata,
mxml_sax_cb_t sax_cb,
void *sax_cbdata
);
.fi
.PP
The nodes in the specified file are added to the specified top node.
If no top node is provided, the XML file MUST be well-formed with a
single parent node like
.URL ?xml ?xml
for the entire file. The callback
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
@ -758,7 +831,10 @@ Load a string into an XML node tree.
mxml_node_t * mxmlLoadString (
mxml_node_t *top,
const char *s,
mxml_load_cb_t cb
mxml_load_cb_t load_cb,
void *load_cbdata,
mxml_sax_cb_t sax_cb,
void *sax_cbdata
);
.fi
.PP
@ -768,8 +844,8 @@ single parent node like
.URL ?xml ?xml
for the entire string. The callback
function returns the value type that should be used for child nodes.
The constants \fBMXML_INTEGER_CALLBACK\fR, \fBMXML_TYPE_OPAQUE_CALLBACK\fR,
\fBMXML_REAL_CALLBACK\fR, and \fBMXML_TYPE_TEXT_CALLBACK\fR are defined for
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
@ -1051,94 +1127,14 @@ int mxmlRetain (
mxml_node_t *node
);
.fi
.SS mxmlSAXLoadFd
Load a file descriptor into an XML node tree
using a SAX callback.
.PP
.nf
mxml_node_t * mxmlSAXLoadFd (
mxml_node_t *top,
int fd,
mxml_load_cb_t cb,
mxml_sax_cb_t sax_cb,
void *sax_data
);
.fi
.PP
The nodes in the specified file are added to the specified top node.
If no top node is provided, the XML file MUST be well-formed with a
single parent node like
.URL ?xml ?xml
for the entire file. The callback
function returns the value type that should be used for child nodes.
The constants \fBMXML_INTEGER_CALLBACK\fR, \fBMXML_TYPE_OPAQUE_CALLBACK\fR,
\fBMXML_REAL_CALLBACK\fR, and \fBMXML_TYPE_TEXT_CALLBACK\fR are defined for
loading child nodes of the specified type.
.PP
The SAX callback must call \fImxmlRetain\fR for any nodes that need to
be kept for later use. Otherwise, nodes are deleted when the parent
node is closed or after each data, comment, CDATA, or directive node.
.SS mxmlSAXLoadFile
Load a file into an XML node tree
using a SAX callback.
.PP
.nf
mxml_node_t * mxmlSAXLoadFile (
mxml_node_t *top,
FILE *fp,
mxml_load_cb_t cb,
mxml_sax_cb_t sax_cb,
void *sax_data
);
.fi
.PP
The nodes in the specified file are added to the specified top node.
If no top node is provided, the XML file MUST be well-formed with a
single parent node like
.URL ?xml ?xml
for the entire file. The callback
function returns the value type that should be used for child nodes.
The constants \fBMXML_INTEGER_CALLBACK\fR, \fBMXML_TYPE_OPAQUE_CALLBACK\fR,
\fBMXML_REAL_CALLBACK\fR, and \fBMXML_TYPE_TEXT_CALLBACK\fR are defined for
loading child nodes of the specified type.
.PP
The SAX callback must call \fImxmlRetain\fR for any nodes that need to
be kept for later use. Otherwise, nodes are deleted when the parent
node is closed or after each data, comment, CDATA, or directive node.
.SS mxmlSAXLoadString
Load a string into an XML node tree
using a SAX callback.
.PP
.nf
mxml_node_t * mxmlSAXLoadString (
mxml_node_t *top,
const char *s,
mxml_load_cb_t cb,
mxml_sax_cb_t sax_cb,
void *sax_data
);
.fi
.PP
The nodes in the specified string are added to the specified top node.
If no top node is provided, the XML string MUST be well-formed with a
single parent node like
.URL ?xml ?xml
for the entire string. The callback
function returns the value type that should be used for child nodes.
The constants \fBMXML_INTEGER_CALLBACK\fR, \fBMXML_TYPE_OPAQUE_CALLBACK\fR,
\fBMXML_REAL_CALLBACK\fR, and \fBMXML_TYPE_TEXT_CALLBACK\fR are defined for
loading child nodes of the specified type.
.PP
The SAX callback must call \fImxmlRetain\fR for any nodes that need to
be kept for later use. Otherwise, nodes are deleted when the parent
node is closed or after each data, comment, CDATA, or directive node.
.SS mxmlSaveAllocString
Save an XML tree to an allocated string.
.PP
.nf
char * mxmlSaveAllocString (
mxml_node_t *node,
mxml_save_cb_t cb
mxml_save_cb_t save_cb,
void *save_cbdata
);
.fi
.PP
@ -1159,7 +1155,8 @@ Save an XML tree to a file descriptor.
bool mxmlSaveFd (
mxml_node_t *node,
int fd,
mxml_save_cb_t cb
mxml_save_cb_t save_cb,
void *save_cbdata
);
.fi
.PP
@ -1175,7 +1172,43 @@ Save an XML tree to a file.
bool mxmlSaveFile (
mxml_node_t *node,
FILE *fp,
mxml_save_cb_t cb
mxml_save_cb_t save_cb,
void *save_cbdata
);
.fi
.PP
The callback argument specifies a function that returns a whitespace
string or NULL before and after each element. If \fBMXML_NO_CALLBACK\fR
is specified, whitespace will only be added before \fBMXML_TYPE_TEXT\fR nodes
with leading whitespace and before attribute names inside opening
element tags.
.SS mxmlSaveFilename
Save an XML tree to a file.
.PP
.nf
bool mxmlSaveFilename (
mxml_node_t *node,
const char *filename,
mxml_save_cb_t save_cb,
void *save_cbdata
);
.fi
.PP
The callback argument specifies a function that returns a whitespace
string or NULL before and after each element. If \fBMXML_NO_CALLBACK\fR
is specified, whitespace will only be added before \fBMXML_TYPE_TEXT\fR nodes
with leading whitespace and before attribute names inside opening
element tags.
.SS mxmlSaveIO
Save an XML tree using a callback.
.PP
.nf
bool mxmlSaveIO (
mxml_node_t *node,
mxml_write_cb_t write_cb,
void *write_cbdata,
mxml_save_cb_t save_cb,
void *save_cbdata
);
.fi
.PP
@ -1192,7 +1225,8 @@ size_t mxmlSaveString (
mxml_node_t *node,
char *buffer,
size_t bufsize,
mxml_save_cb_t cb
mxml_save_cb_t save_cb,
void *save_cbdata
);
.fi
.PP
@ -1457,19 +1491,19 @@ typedef void(*)(void *) mxml_custom_destroy_cb_t;
Custom data load callback function
.PP
.nf
typedef bool(*)(mxml_node_t *, const char *) mxml_custom_load_cb_t;
typedef bool(*)(mxml_node_t *node const char *s) mxml_custom_load_cb_t;
.fi
.SS mxml_custom_save_cb_t
Custom data save callback function
.PP
.nf
typedef char *(*)(mxml_node_t *) mxml_custom_save_cb_t;
typedef char *(*)(mxml_node_t *node) mxml_custom_save_cb_t;
.fi
.SS mxml_entity_cb_t
Entity callback function
.PP
.nf
typedef int(*)(const char *) mxml_entity_cb_t;
typedef int(*)(const char *name) mxml_entity_cb_t;
.fi
.SS mxml_error_cb_t
Error callback function
@ -1487,7 +1521,7 @@ typedef struct _mxml_index_s mxml_index_t;
Load callback function
.PP
.nf
typedef mxml_type_t(*)(mxml_node_t *) mxml_load_cb_t;
typedef mxml_type_t(*)(void *cbdata mxml_node_t *node) mxml_load_cb_t;
.fi
.SS mxml_node_t
An XML node.
@ -1495,17 +1529,23 @@ An XML node.
.nf
typedef struct _mxml_node_s mxml_node_t;
.fi
.SS mxml_read_cb_t
Read callback function
.PP
.nf
typedef ssize_t(*)(void *cbdata void *buffer size_t bytes) mxml_read_cb_t;
.fi
.SS mxml_save_cb_t
Save callback function
.PP
.nf
typedef const char *(*)(mxml_node_t *, int) mxml_save_cb_t;
typedef const char *(*)(void *cbdata mxml_node_t *node mxml_ws_t when) mxml_save_cb_t;
.fi
.SS mxml_sax_cb_t
SAX callback function
.PP
.nf
typedef bool(*)(mxml_node_t *, mxml_sax_event_t, void *) mxml_sax_cb_t;
typedef bool(*)(void *cbdata mxml_node_t *node mxml_sax_event_t event) mxml_sax_cb_t;
.fi
.SS mxml_sax_event_t
SAX event type.
@ -1519,6 +1559,18 @@ The XML node type.
.nf
typedef enum mxml_type_e mxml_type_t;
.fi
.SS mxml_write_cb_t
Write callback function
.PP
.nf
typedef ssize_t(*)(void *cbdata const void *buffer size_t bytes) mxml_write_cb_t;
.fi
.SS mxml_ws_t
Whitespace periods
.PP
.nf
typedef enum mxml_ws_e mxml_ws_t;
.fi
.SH SEE ALSO
Mini-XML Programmers Manual, https://www.msweet.org/mxml
.SH COPYRIGHT

Binary file not shown.

@ -292,7 +292,6 @@ span.string {
<li><a href="#mxmlElementSetAttr">mxmlElementSetAttr</a></li>
<li><a href="#mxmlElementSetAttrf">mxmlElementSetAttrf</a></li>
<li><a href="#mxmlEntityAddCallback">mxmlEntityAddCallback</a></li>
<li><a href="#mxmlEntityGetName">mxmlEntityGetName</a></li>
<li><a href="#mxmlEntityGetValue">mxmlEntityGetValue</a></li>
<li><a href="#mxmlEntityRemoveCallback">mxmlEntityRemoveCallback</a></li>
<li><a href="#mxmlFindElement">mxmlFindElement</a></li>
@ -323,6 +322,8 @@ span.string {
<li><a href="#mxmlIndexReset">mxmlIndexReset</a></li>
<li><a href="#mxmlLoadFd">mxmlLoadFd</a></li>
<li><a href="#mxmlLoadFile">mxmlLoadFile</a></li>
<li><a href="#mxmlLoadFilename">mxmlLoadFilename</a></li>
<li><a href="#mxmlLoadIO">mxmlLoadIO</a></li>
<li><a href="#mxmlLoadString">mxmlLoadString</a></li>
<li><a href="#mxmlNewCDATA">mxmlNewCDATA</a></li>
<li><a href="#mxmlNewCDATAf">mxmlNewCDATAf</a></li>
@ -344,12 +345,11 @@ span.string {
<li><a href="#mxmlRelease">mxmlRelease</a></li>
<li><a href="#mxmlRemove">mxmlRemove</a></li>
<li><a href="#mxmlRetain">mxmlRetain</a></li>
<li><a href="#mxmlSAXLoadFd">mxmlSAXLoadFd</a></li>
<li><a href="#mxmlSAXLoadFile">mxmlSAXLoadFile</a></li>
<li><a href="#mxmlSAXLoadString">mxmlSAXLoadString</a></li>
<li><a href="#mxmlSaveAllocString">mxmlSaveAllocString</a></li>
<li><a href="#mxmlSaveFd">mxmlSaveFd</a></li>
<li><a href="#mxmlSaveFile">mxmlSaveFile</a></li>
<li><a href="#mxmlSaveFilename">mxmlSaveFilename</a></li>
<li><a href="#mxmlSaveIO">mxmlSaveIO</a></li>
<li><a href="#mxmlSaveString">mxmlSaveString</a></li>
<li><a href="#mxmlSetCDATA">mxmlSetCDATA</a></li>
<li><a href="#mxmlSetCDATAf">mxmlSetCDATAf</a></li>
@ -383,14 +383,18 @@ span.string {
<li><a href="#mxml_index_t">mxml_index_t</a></li>
<li><a href="#mxml_load_cb_t">mxml_load_cb_t</a></li>
<li><a href="#mxml_node_t">mxml_node_t</a></li>
<li><a href="#mxml_read_cb_t">mxml_read_cb_t</a></li>
<li><a href="#mxml_save_cb_t">mxml_save_cb_t</a></li>
<li><a href="#mxml_sax_cb_t">mxml_sax_cb_t</a></li>
<li><a href="#mxml_sax_event_t">mxml_sax_event_t</a></li>
<li><a href="#mxml_type_t">mxml_type_t</a></li>
<li><a href="#mxml_write_cb_t">mxml_write_cb_t</a></li>
<li><a href="#mxml_ws_t">mxml_ws_t</a></li>
</ul></li>
<li><a href="#ENUMERATIONS">Enumerations</a><ul class="subcontents">
<li><a href="#mxml_sax_event_e">mxml_sax_event_e</a></li>
<li><a href="#mxml_type_e">mxml_type_e</a></li>
<li><a href="#mxml_ws_e">mxml_ws_e</a></li>
</ul></li>
</ul>
</div>
@ -443,41 +447,41 @@ span.string {
<p>You load an XML file using the <code>mxmlLoadFile</code> function:</p>
<pre><code class="language-c">mxml_node_t *
mxmlLoadFile(mxml_node_t *top, FILE *fp,
mxml_type_t (*cb)(mxml_node_t *));
mxml_load_cb_t load_cb, <span class="reserved">void</span> *load_cbdata,
mxml_sax_cb_t sax_cb, <span class="reserved">void</span> *sax_cbdata);
</code></pre>
<p>The <code>cb</code> argument specifies a function that assigns child (value) node types for each element in the document. The callback can be a function you provide or one of the standard functions provided with Mini-XML. For example, to load the XML file &quot;filename.xml&quot; containing text strings you can use the <code>MXML_OPAQUE_CALLBACK</code> function:</p>
<p>The <code>load_cb</code> argument specifies a function that assigns child (value) node types for each element in the document. The default callback (<code>NULL</code>) supports passing a pointer to an <code>mxml_type_t</code> variable containing the type of value nodes. For example, to load the XML file &quot;filename.xml&quot; containing literal strings you can use:</p>
<pre><code class="language-c">FILE *fp;
mxml_node_t *tree;
mxml_type_t type = MXML_TYPE_OPAQUE;
fp = fopen(<span class="string">&quot;filename.xml&quot;</span>, <span class="string">&quot;r&quot;</span>);
tree = mxmlLoadFile(NULL, fp, MXML_OPAQUE_CALLBACK);
tree = mxmlLoadFile(<span class="comment">/*top*/</span>NULL, fp, <span class="comment">/*load_cb*/</span>NULL, &amp;type,
<span class="comment">/*sax_cb*/</span>NULL, <span class="comment">/*sax_cbdata*/</span>NULL);
fclose(fp);
</code></pre>
<p>Mini-XML also provides functions to load from a file descriptor or string:</p>
<p>Mini-XML also provides functions to load from a named file, a file descriptor, or string:</p>
<pre><code class="language-c">mxml_node_t *
mxmlLoadFd(mxml_node_t *top, <span class="reserved">int</span> fd,
mxml_type_t (*cb)(mxml_node_t *));
mxml_load_cb_t load_cb, <span class="reserved">void</span> *load_cbdata,
mxml_sax_cb_t sax_cb, <span class="reserved">void</span> *sax_cbdata);
mxml_node_t *
mxmlLoadFilename(mxml_node_t *top, <span class="reserved">const</span> <span class="reserved">char</span> *filename,
mxml_load_cb_t load_cb, <span class="reserved">void</span> *load_cbdata,
mxml_sax_cb_t sax_cb, <span class="reserved">void</span> *sax_cbdata);
mxml_node_t *
mxmlLoadString(mxml_node_t *top, <span class="reserved">const</span> <span class="reserved">char</span> *s,
mxml_type_t (*cb)(mxml_node_t *));
mxml_load_cb_t load_cb, <span class="reserved">void</span> *load_cbdata,
mxml_sax_cb_t sax_cb, <span class="reserved">void</span> *sax_cbdata);
</code></pre>
<h4 id="load-callbacks">Load Callbacks</h4>
<p>The last argument to the <code>mxmlLoad</code> functions is a callback function which is used to determine the value type of each data node in an XML document. Mini-XML defines several standard callbacks for simple XML data files:</p>
<ul>
<li><p><code>MXML_INTEGER_CALLBACK</code>: All data nodes contain whitespace-separated integers.</p>
</li>
<li><p><code>MXML_OPAQUE_CALLBACK</code>: All data nodes contain opaque strings with whitespace preserved.</p>
</li>
<li><p><code>MXML_REAL_CALLBACK</code> - All data nodes contain whitespace-separated floating-point numbers.</p>
</li>
<li><p><code>MXML_TEXT_CALLBACK</code> - All data nodes contain whitespace-separated strings.</p>
</li>
</ul>
<p>The <code>load_xxx</code> arguments to the <code>mxmlLoad</code> functions are a callback function and a data pointer which are used to determine the value type of each data node in an XML document. The default (<code>NULL</code>) callback expects the <code>load_cbdata</code> argument to be a pointer to a <code>mxml_type_t</code> variable - if <code>NULL</code> it returns the <code>MXML_TYPE_TEXT</code> type.</p>
<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: <code>MXML_TYPE_CUSTOM</code>, <code>MXML_TYPE_INTEGER</code>, <code>MXML_TYPE_OPAQUE</code>, <code>MXML_TYPE_REAL</code>, or <code>MXML_TYPE_TEXT</code>. The function is called <em>after</em> 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>
<p>The following callback function looks for an attribute named &quot;type&quot; or the element name to determine the value type for its child nodes:</p>
<pre><code class="language-c">mxml_type_t
type_cb(mxml_node_t *node)
type_cb(<span class="reserved">void</span> *cbdata, mxml_node_t *node)
{
<span class="reserved">const</span> <span class="reserved">char</span> *type;
@ -505,7 +509,9 @@ type_cb(mxml_node_t *node)
mxml_node_t *tree;
fp = fopen(<span class="string">&quot;filename.xml&quot;</span>, <span class="string">&quot;r&quot;</span>);
tree = mxmlLoadFile(NULL, fp, type_cb);
tree = mxmlLoadFile(<span class="comment">/*top*/</span>NULL, fp,
type_cb, <span class="comment">/*load_cbdata*/</span>NULL,
<span class="comment">/*sax_cb*/</span>NULL, <span class="comment">/*sax_cbata*/</span>NULL);
fclose(fp);
</code></pre>
<h3 class="title" id="nodes">Nodes</h3>
@ -924,7 +930,7 @@ mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top,
}
</code></pre>
<p>The nodes will be returned in the following order:</p>
<pre><code class="language-c">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;utf-8&quot;</span>?&gt;
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;data&gt;
&lt;node&gt;
val1
@ -988,37 +994,29 @@ mxmlIndexGetCount(mxml_index_t *ind);
mxmlIndexDelete(mxml_index_t *ind);
</code></pre>
<h2 class="title" id="custom-data-types">Custom Data Types</h2>
<p>Mini-XML supports -------------------- data types via per-thread load and save callbacks. Only a single set of callbacks can be active at any time for the current thread, however your callbacks can store additional information in order to support multiple -------------------- data types as needed. The <code>MXML_TYPE_CUSTOM</code> node type identifies -------------------- data nodes.</p>
<p>The <code>mxmlGetCustom</code> function retrieves the -------------------- value pointer for a node.</p>
<p>Mini-XML supports custom data types via per-thread load and save callbacks. Only a single set of callbacks can be active at any time for the current thread, however your callbacks can store additional information in order to support multiple custom data types as needed. The <code>MXML_TYPE_CUSTOM</code> node type identifies custom data nodes.</p>
<p>The <code>mxmlGetCustom</code> function retrieves the custom value pointer for a node.</p>
<pre><code class="language-c"><span class="reserved">const</span> <span class="reserved">void</span> *
mxmlGetCustom(mxml_node_t *node);
</code></pre>
<p>Custom (<code>MXML_TYPE_CUSTOM</code>) nodes are created using the <code>mxmlNewCustom</code> function or using a -------------------- per-thread load callbacks specified using the <code>mxmlSetCustomHandlers</code> function:</p>
<pre><code class="language-c"><span class="reserved">typedef</span> <span class="reserved">void</span> (*mxml_
--------------------_destroy_cb_t)(<span class="reserved">void</span> *);
<span class="reserved">typedef</span> <span class="reserved">bool</span> (*mxml_
--------------------_load_cb_t)(mxml_node_t *, <span class="reserved">const</span> <span class="reserved">char</span> *);
<span class="reserved">typedef</span> <span class="reserved">char</span> *(*mxml_
--------------------_save_cb_t)(mxml_node_t *);
<p>Custom (<code>MXML_TYPE_CUSTOM</code>) nodes are created using the <code>mxmlNewCustom</code> function or using a custom per-thread load callbacks specified using the <code>mxmlSetCustomHandlers</code> function:</p>
<pre><code class="language-c"><span class="reserved">typedef</span> <span class="reserved">void</span> (*mxml_custom_destroy_cb_t)(<span class="reserved">void</span> *);
<span class="reserved">typedef</span> <span class="reserved">bool</span> (*mxml_custom_load_cb_t)(mxml_node_t *, <span class="reserved">const</span> <span class="reserved">char</span> *);
<span class="reserved">typedef</span> <span class="reserved">char</span> *(*mxml_custom_save_cb_t)(mxml_node_t *);
mxml_node_t *
mxmlNewCustom(mxml_node_t *parent, <span class="reserved">void</span> *data,
mxml_
--------------------_destroy_cb_t destroy);
mxml_custom_destroy_cb_t destroy);
<span class="reserved">int</span>
mxmlSetCustom(mxml_node_t *node, <span class="reserved">void</span> *data,
mxml_
--------------------_destroy_cb_t destroy);
mxml_custom_destroy_cb_t destroy);
<span class="reserved">void</span>
mxmlSetCustomHandlers(mxml_
--------------------_load_cb_t load,
mxml_
--------------------_save_cb_t save);
mxmlSetCustomHandlers(mxml_custom_load_cb_t load,
mxml_custom_save_cb_t save);
</code></pre>
<p>The load callback receives a pointer to the current data node and a string of opaque character data from the XML source with character entities converted to the corresponding UTF-8 characters. For example, if we wanted to support a</p>
<p>-------------------- date/time type whose value is encoded as &quot;yyyy-mm-ddThh:mm:ssZ&quot; (ISO format), the load callback would look like the following:</p>
<p>The load callback receives a pointer to the current data node and a string of opaque character data from the XML source with character entities converted to the corresponding UTF-8 characters. For example, if we wanted to support a custom date/time type whose value is encoded as &quot;yyyy-mm-ddThh:mm:ssZ&quot; (ISO format), the load callback would look like the following:</p>
<pre><code class="language-c"><span class="reserved">typedef</span> <span class="reserved">struct</span>
{
<span class="reserved">unsigned</span> year, <span class="comment">/* Year */</span>
@ -1031,8 +1029,7 @@ mxmlSetCustomHandlers(mxml_
} iso_date_time_t;
<span class="reserved">bool</span>
load_
--------------------(mxml_node_t *node, <span class="reserved">const</span> <span class="reserved">char</span> *data)
load_custom(mxml_node_t *node, <span class="reserved">const</span> <span class="reserved">char</span> *data)
{
iso_date_time_t *dt;
<span class="reserved">struct</span> tm tmdata;
@ -1094,8 +1091,7 @@ load_
dt-&gt;unix = gmtime(&amp;tmdata);
<span class="comment">/*</span>
<span class="comment"> * Assign</span>
<span class="comment">-------------------- node data and destroy (free) function</span>
<span class="comment"> * Assign custom node data and destroy (free) function</span>
<span class="comment"> * pointers...</span>
<span class="comment"> */</span>
@ -1108,11 +1104,10 @@ load_
<span class="reserved">return</span> (<span class="reserved">true</span>);
}
</code></pre>
<p>The function itself can return <code>true</code> on success or <code>false</code> if it is unable to decode the -------------------- data or the data contains an error. Custom data nodes contain a <code>void</code> pointer to the allocated -------------------- data for the node and a pointer to a destructor function which will free the -------------------- data when the node is deleted. In this example, we use the standard <code>free</code> function since everything is contained in a single calloc'd block.</p>
<p>The save callback receives the node pointer and returns an allocated string containing the -------------------- data value. The following save callback could be used for our ISO date/time type:</p>
<p>The function itself can return <code>true</code> on success or <code>false</code> if it is unable to decode the custom data or the data contains an error. Custom data nodes contain a <code>void</code> pointer to the allocated custom data for the node and a pointer to a destructor function which will free the custom data when the node is deleted. In this example, we use the standard <code>free</code> function since everything is contained in a single calloc'd block.</p>
<p>The save callback receives the node pointer and returns an allocated string containing the custom data value. The following save callback could be used for our ISO date/time type:</p>
<pre><code class="language-c"><span class="reserved">char</span> *
save_
--------------------(mxml_node_t *node)
save_custom(mxml_node_t *node)
{
<span class="reserved">char</span> data[<span class="number">255</span>];
iso_date_time_t *dt;
@ -1129,32 +1124,14 @@ save_
}
</code></pre>
<p>You register the callback functions using the <code>mxmlSetCustomHandlers</code> function:</p>
<pre><code class="language-c">mxmlSetCustomHandlers(load_
--------------------, save_
--------------------);
<pre><code class="language-c">mxmlSetCustomHandlers(load_custom, save_custom);
</code></pre>
<h2 class="title" id="sax-stream-loading-of-documents">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 a stream of nodes. Aside from allowing you to process XML documents of any size, the Mini-XML implementation also allows you to retain portions of the document in memory for later processing.</p>
<p>The <code>mxmlSAXLoadFd</code>, <code>mxmlSAXLoadFile</code>, and <code>mxmlSAXLoadString</code> functions provide the SAX loading APIs:</p>
<pre><code class="language-c">mxml_node_t *
mxmlSAXLoadFd(mxml_node_t *top, <span class="reserved">int</span> fd,
mxml_type_t (*cb)(mxml_node_t *),
mxml_sax_cb_t sax, <span class="reserved">void</span> *sax_data);
mxml_node_t *
mxmlSAXLoadFile(mxml_node_t *top, FILE *fp,
mxml_type_t (*cb)(mxml_node_t *),
mxml_sax_cb_t sax, <span class="reserved">void</span> *sax_data);
mxml_node_t *
mxmlSAXLoadString(mxml_node_t *top, <span class="reserved">const</span> <span class="reserved">char</span> *s,
mxml_type_t (*cb)(mxml_node_t *),
mxml_sax_cb_t sax, <span class="reserved">void</span> *sax_data);
</code></pre>
<p>Each function works like the corresponding <code>mxmlLoad</code> function but uses a callback to process each node as it is read. The callback function receives the node, an event code, and a user data pointer you supply and returns <code>true</code> to continue processing or <code>false</code> to stop:</p>
<p>The <code>mxmlLoadFd</code>, <code>mxmlLoadFile</code>, <code>mxmlLoadFilename</code>, <code>mxmlLoadIO</code>, and <code>mxmlLoadString</code> functions support a SAX callback and associated data. The callback function receives the data pointer you supplied, the node, and an event code and returns <code>true</code> to continue processing or <code>false</code> to stop:</p>
<pre><code class="language-c"><span class="reserved">bool</span>
sax_cb(mxml_node_t *node, mxml_sax_event_t event,
<span class="reserved">void</span> *data)
sax_cb(<span class="reserved">void</span> *cbdata, mxml_node_t *node,
mxml_sax_event_t event)
{
... <span class="reserved">do</span> something ...
@ -1181,8 +1158,7 @@ sax_cb(mxml_node_t *node, mxml_sax_event_t event,
</ul>
<p>Elements are <em>released</em> after the close element is processed. All other nodes are released after they are processed. The SAX callback can <em>retain</em> the node using the <code>mxmlRetain</code> function. For example, the following SAX callback will retain all nodes, effectively simulating a normal in-memory load:</p>
<pre><code class="language-c"><span class="reserved">bool</span>
sax_cb(mxml_node_t *node, mxml_sax_event_t event,
<span class="reserved">void</span> *data)
sax_cb(<span class="reserved">void</span> *cbdata, mxml_node_t *node, mxml_sax_event_t event)
{
<span class="reserved">if</span> (event != MXML_SAX_ELEMENT_CLOSE)
mxmlRetain(node);
@ -1192,8 +1168,8 @@ sax_cb(mxml_node_t *node, mxml_sax_event_t event,
</code></pre>
<p>More typically the SAX callback will only retain a small portion of the document that is needed for post-processing. For example, the following SAX callback will retain the title and headings in an XHTML file. It also retains the (parent) elements like <code>&lt;html&gt;</code>, <code>&lt;head&gt;</code>, and <code>&lt;body&gt;</code>, and processing directives like <code>&lt;?xml ... ?&gt;</code> and declarations like <code>&lt;!DOCTYPE ... &gt;</code>:</p>
<pre><code class="language-c"><span class="reserved">bool</span>
sax_cb(mxml_node_t *node, mxml_sax_event_t event,
<span class="reserved">void</span> *data)
sax_cb(<span class="reserved">void</span> *cbdata, mxml_node_t *node,
mxml_sax_event_t event)
{
<span class="reserved">if</span> (event == MXML_SAX_ELEMENT_OPEN)
{
@ -1235,11 +1211,12 @@ sax_cb(mxml_node_t *node, mxml_sax_event_t event,
<span class="reserved">return</span> (<span class="reserved">true</span>);
}
</code></pre>
<p>The resulting skeleton document tree can then be searched just like one loaded using the <code>mxmlLoad</code> functions. For example, a filter that reads an XHTML document from stdin and then shows the title and headings in the document would look like:</p>
<p>The resulting skeleton document tree can then be searched just like one loaded without the SAX callback function. For example, a filter that reads an XHTML document from stdin and then shows the title and headings in the document would look like:</p>
<pre><code class="language-c">mxml_node_t *doc, *title, *body, *heading;
doc = mxmlSAXLoadFd(NULL, <span class="number">0</span>, MXML_TEXT_CALLBACK, sax_cb,
NULL);
doc = mxmlLoadFd(<span class="comment">/*top*/</span>NULL, <span class="comment">/*fd*/</span><span class="number">0</span>,
<span class="comment">/*load_cb*/</span>NULL, <span class="comment">/*load_cbdata*/</span>NULL,
sax_cb, <span class="comment">/*sax_cbdata*/</span>NULL);
title = mxmlFindElement(doc, doc, <span class="string">&quot;title&quot;</span>, NULL, NULL,
MXML_DESCEND);
@ -1288,6 +1265,8 @@ print_children(mxml_node_t *parent)
</li>
<li><p>SAX callbacks now return a boolean value.</p>
</li>
<li><p>The <code>mxmlSAXLoadXxx</code> functions have been removed in favor of passing the SAX callback function and data pointers to the <code>mxmlLoadXxx</code> functions.</p>
</li>
<li><p>Node types are now named <code>MXML_TYPE_foo</code> instead of <code>MXML_foo</code>.</p>
</li>
<li><p>Functions that returned <code>0</code> on success and <code>-1</code> on error now return <code>true</code> on success and <code>false</code> on error.</p>
@ -1445,19 +1424,6 @@ bool mxmlEntityAddCallback(<a href="#mxml_entity_cb_t">mxml_entity_cb_t</a> cb);
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on failure</p>
<h3 class="function"><a id="mxmlEntityGetName">mxmlEntityGetName</a></h3>
<p class="description">Get the name that corresponds to the character value.</p>
<p class="code">
const char *mxmlEntityGetName(int val);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>val</th>
<td class="description">Character value</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">Entity name or <code>NULL</code></p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">If val does not need to be represented by a named entity, <code>NULL</code> is returned.</p>
<h3 class="function"><a id="mxmlEntityGetValue">mxmlEntityGetValue</a></h3>
<p class="description">Get the character corresponding to a named entity.</p>
<p class="code">
@ -1825,7 +1791,7 @@ to calling <a href="#mxmlIndexEnum"><code>mxmlIndexEnum</code></a>.</p>
<h3 class="function"><a id="mxmlIndexGetCount">mxmlIndexGetCount</a></h3>
<p class="description">Get the number of nodes in an index.</p>
<p class="code">
int mxmlIndexGetCount(<a href="#mxml_index_t">mxml_index_t</a> *ind);</p>
size_t mxmlIndexGetCount(<a href="#mxml_index_t">mxml_index_t</a> *ind);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>ind</th>
@ -1872,15 +1838,21 @@ argument is not NULL.</p>
<h3 class="function"><a id="mxmlLoadFd">mxmlLoadFd</a></h3>
<p class="description">Load a file descriptor into an XML node tree.</p>
<p class="code">
<a href="#mxml_node_t">mxml_node_t</a> *mxmlLoadFd(<a href="#mxml_node_t">mxml_node_t</a> *top, int fd, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> cb);</p>
<a href="#mxml_node_t">mxml_node_t</a> *mxmlLoadFd(<a href="#mxml_node_t">mxml_node_t</a> *top, int fd, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> load_cb, void *load_cbdata, <a href="#mxml_sax_cb_t">mxml_sax_cb_t</a> sax_cb, void *sax_cbdata);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>top</th>
<td class="description">Top node</td></tr>
<tr><th>fd</th>
<td class="description">File descriptor to read from</td></tr>
<tr><th>cb</th>
<td class="description">Callback function or constant</td></tr>
<tr><th>load_cb</th>
<td class="description">Load callback function or <code>NULL</code></td></tr>
<tr><th>load_cbdata</th>
<td class="description">Load callback data</td></tr>
<tr><th>sax_cb</th>
<td class="description">SAX callback function or <code>NULL</code><code></code></td></tr>
<tr><th>sax_cbdata</th>
<td class="description">SAX callback data</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">First node or <code>NULL</code> if the file could not be read.</p>
@ -1889,8 +1861,8 @@ argument is not NULL.</p>
If no top node is provided, the XML file MUST be well-formed with a
single parent node like <a href="?xml">?xml</a> 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_TYPE_OPAQUE_CALLBACK</code>,
<code>MXML_REAL_CALLBACK</code>, and <code>MXML_TYPE_TEXT_CALLBACK</code> are defined for
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.<br>
<br>
Note: The most common programming error when using the Mini-XML library is
@ -1901,15 +1873,21 @@ text as a series of whitespace-delimited words, instead of using the
<h3 class="function"><a id="mxmlLoadFile">mxmlLoadFile</a></h3>
<p class="description">Load a file into an XML node tree.</p>
<p class="code">
<a href="#mxml_node_t">mxml_node_t</a> *mxmlLoadFile(<a href="#mxml_node_t">mxml_node_t</a> *top, FILE *fp, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> cb);</p>
<a href="#mxml_node_t">mxml_node_t</a> *mxmlLoadFile(<a href="#mxml_node_t">mxml_node_t</a> *top, FILE *fp, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> load_cb, void *load_cbdata, <a href="#mxml_sax_cb_t">mxml_sax_cb_t</a> sax_cb, void *sax_cbdata);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>top</th>
<td class="description">Top node</td></tr>
<tr><th>fp</th>
<td class="description">File to read from</td></tr>
<tr><th>cb</th>
<td class="description">Callback function or constant</td></tr>
<tr><th>load_cb</th>
<td class="description">Load callback function or <code>NULL</code></td></tr>
<tr><th>load_cbdata</th>
<td class="description">Load callback data</td></tr>
<tr><th>sax_cb</th>
<td class="description">SAX callback function or <code>NULL</code><code></code></td></tr>
<tr><th>sax_cbdata</th>
<td class="description">SAX callback data</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">First node or <code>NULL</code> if the file could not be read.</p>
@ -1918,8 +1896,80 @@ text as a series of whitespace-delimited words, instead of using the
If no top node is provided, the XML file MUST be well-formed with a
single parent node like <a href="?xml">?xml</a> 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_TYPE_OPAQUE_CALLBACK</code>,
<code>MXML_REAL_CALLBACK</code>, and <code>MXML_TYPE_TEXT_CALLBACK</code> are defined for
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.<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="mxmlLoadFilename">mxmlLoadFilename</a></h3>
<p class="description">Load a file into an XML node tree.</p>
<p class="code">
<a href="#mxml_node_t">mxml_node_t</a> *mxmlLoadFilename(<a href="#mxml_node_t">mxml_node_t</a> *top, const char *filename, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> load_cb, void *load_cbdata, <a href="#mxml_sax_cb_t">mxml_sax_cb_t</a> sax_cb, void *sax_cbdata);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>top</th>
<td class="description">Top node</td></tr>
<tr><th>filename</th>
<td class="description">File to read from</td></tr>
<tr><th>load_cb</th>
<td class="description">Load callback function or <code>NULL</code></td></tr>
<tr><th>load_cbdata</th>
<td class="description">Load callback data</td></tr>
<tr><th>sax_cb</th>
<td class="description">SAX callback function or <code>NULL</code><code></code></td></tr>
<tr><th>sax_cbdata</th>
<td class="description">SAX callback data</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">First node or <code>NULL</code> if the file could not be read.</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">The nodes in the specified file are added to the specified top node.
If no top node is provided, the XML file MUST be well-formed with a
single parent node like <a href="?xml">?xml</a> 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.<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="mxmlLoadIO">mxmlLoadIO</a></h3>
<p class="description">Load an XML node tree using a read callback.</p>
<p class="code">
<a href="#mxml_node_t">mxml_node_t</a> *mxmlLoadIO(<a href="#mxml_node_t">mxml_node_t</a> *top, <a href="#mxml_read_cb_t">mxml_read_cb_t</a> read_cb, void *read_cbdata, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> load_cb, void *load_cbdata, <a href="#mxml_sax_cb_t">mxml_sax_cb_t</a> sax_cb, void *sax_cbdata);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>top</th>
<td class="description">Top node</td></tr>
<tr><th>read_cb</th>
<td class="description">Read callback function</td></tr>
<tr><th>read_cbdata</th>
<td class="description">Read callback data</td></tr>
<tr><th>load_cb</th>
<td class="description">Load callback function or <code>NULL</code></td></tr>
<tr><th>load_cbdata</th>
<td class="description">Load callback data</td></tr>
<tr><th>sax_cb</th>
<td class="description">SAX callback function or <code>NULL</code><code></code></td></tr>
<tr><th>sax_cbdata</th>
<td class="description">SAX callback data</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">First node or <code>NULL</code> if the file could not be read.</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">The nodes in the specified file are added to the specified top node.
If no top node is provided, the XML file MUST be well-formed with a
single parent node like <a href="?xml">?xml</a> 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.<br>
<br>
Note: The most common programming error when using the Mini-XML library is
@ -1930,15 +1980,21 @@ text as a series of whitespace-delimited words, instead of using the
<h3 class="function"><a id="mxmlLoadString">mxmlLoadString</a></h3>
<p class="description">Load a string into an XML node tree.</p>
<p class="code">
<a href="#mxml_node_t">mxml_node_t</a> *mxmlLoadString(<a href="#mxml_node_t">mxml_node_t</a> *top, const char *s, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> cb);</p>
<a href="#mxml_node_t">mxml_node_t</a> *mxmlLoadString(<a href="#mxml_node_t">mxml_node_t</a> *top, const char *s, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> load_cb, void *load_cbdata, <a href="#mxml_sax_cb_t">mxml_sax_cb_t</a> sax_cb, void *sax_cbdata);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>top</th>
<td class="description">Top node</td></tr>
<tr><th>s</th>
<td class="description">String to load</td></tr>
<tr><th>cb</th>
<td class="description">Callback function or constant</td></tr>
<tr><th>load_cb</th>
<td class="description">Load callback function or <code>NULL</code></td></tr>
<tr><th>load_cbdata</th>
<td class="description">Load callback data</td></tr>
<tr><th>sax_cb</th>
<td class="description">SAX callback function or <code>NULL</code><code></code></td></tr>
<tr><th>sax_cbdata</th>
<td class="description">SAX callback data</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">First node or <code>NULL</code> if the string has errors.</p>
@ -1947,8 +2003,8 @@ text as a series of whitespace-delimited words, instead of using the
If no top node is provided, the XML string MUST be well-formed with a
single parent node like <a href="?xml">?xml</a> 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_TYPE_OPAQUE_CALLBACK</code>,
<code>MXML_REAL_CALLBACK</code>, and <code>MXML_TYPE_TEXT_CALLBACK</code> are defined for
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.<br>
<br>
Note: The most common programming error when using the Mini-XML library is
@ -2313,112 +2369,18 @@ int mxmlRetain(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">New reference count</p>
<h3 class="function"><a id="mxmlSAXLoadFd">mxmlSAXLoadFd</a></h3>
<p class="description">Load a file descriptor into an XML node tree
using a SAX callback.</p>
<p class="code">
<a href="#mxml_node_t">mxml_node_t</a> *mxmlSAXLoadFd(<a href="#mxml_node_t">mxml_node_t</a> *top, int fd, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> cb, <a href="#mxml_sax_cb_t">mxml_sax_cb_t</a> sax_cb, void *sax_data);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>top</th>
<td class="description">Top node</td></tr>
<tr><th>fd</th>
<td class="description">File descriptor to read from</td></tr>
<tr><th>cb</th>
<td class="description">Callback function or constant</td></tr>
<tr><th>sax_cb</th>
<td class="description">SAX callback or <code>MXML_NO_CALLBACK</code></td></tr>
<tr><th>sax_data</th>
<td class="description">SAX user data</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">First node or <code>NULL</code> if the file could not be read.</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">The nodes in the specified file are added to the specified top node.
If no top node is provided, the XML file MUST be well-formed with a
single parent node like <a href="?xml">?xml</a> 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_TYPE_OPAQUE_CALLBACK</code>,
<code>MXML_REAL_CALLBACK</code>, and <code>MXML_TYPE_TEXT_CALLBACK</code> are defined for
loading child nodes of the specified type.<br>
<br>
The SAX callback must call <a href="#mxmlRetain"><code>mxmlRetain</code></a> for any nodes that need to
be kept for later use. Otherwise, nodes are deleted when the parent
node is closed or after each data, comment, CDATA, or directive node.</p>
<h3 class="function"><a id="mxmlSAXLoadFile">mxmlSAXLoadFile</a></h3>
<p class="description">Load a file into an XML node tree
using a SAX callback.</p>
<p class="code">
<a href="#mxml_node_t">mxml_node_t</a> *mxmlSAXLoadFile(<a href="#mxml_node_t">mxml_node_t</a> *top, FILE *fp, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> cb, <a href="#mxml_sax_cb_t">mxml_sax_cb_t</a> sax_cb, void *sax_data);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>top</th>
<td class="description">Top node</td></tr>
<tr><th>fp</th>
<td class="description">File to read from</td></tr>
<tr><th>cb</th>
<td class="description">Callback function or constant</td></tr>
<tr><th>sax_cb</th>
<td class="description">SAX callback or <code>MXML_NO_CALLBACK</code></td></tr>
<tr><th>sax_data</th>
<td class="description">SAX user data</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">First node or <code>NULL</code> if the file could not be read.</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">The nodes in the specified file are added to the specified top node.
If no top node is provided, the XML file MUST be well-formed with a
single parent node like <a href="?xml">?xml</a> 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_TYPE_OPAQUE_CALLBACK</code>,
<code>MXML_REAL_CALLBACK</code>, and <code>MXML_TYPE_TEXT_CALLBACK</code> are defined for
loading child nodes of the specified type.<br>
<br>
The SAX callback must call <a href="#mxmlRetain"><code>mxmlRetain</code></a> for any nodes that need to
be kept for later use. Otherwise, nodes are deleted when the parent
node is closed or after each data, comment, CDATA, or directive node.</p>
<h3 class="function"><a id="mxmlSAXLoadString">mxmlSAXLoadString</a></h3>
<p class="description">Load a string into an XML node tree
using a SAX callback.</p>
<p class="code">
<a href="#mxml_node_t">mxml_node_t</a> *mxmlSAXLoadString(<a href="#mxml_node_t">mxml_node_t</a> *top, const char *s, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> cb, <a href="#mxml_sax_cb_t">mxml_sax_cb_t</a> sax_cb, void *sax_data);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>top</th>
<td class="description">Top node</td></tr>
<tr><th>s</th>
<td class="description">String to load</td></tr>
<tr><th>cb</th>
<td class="description">Callback function or constant</td></tr>
<tr><th>sax_cb</th>
<td class="description">SAX callback or <code>MXML_NO_CALLBACK</code></td></tr>
<tr><th>sax_data</th>
<td class="description">SAX user data</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">First node or <code>NULL</code> if the string has errors.</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">The nodes in the specified string are added to the specified top node.
If no top node is provided, the XML string MUST be well-formed with a
single parent node like <a href="?xml">?xml</a> 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_TYPE_OPAQUE_CALLBACK</code>,
<code>MXML_REAL_CALLBACK</code>, and <code>MXML_TYPE_TEXT_CALLBACK</code> are defined for
loading child nodes of the specified type.<br>
<br>
The SAX callback must call <a href="#mxmlRetain"><code>mxmlRetain</code></a> for any nodes that need to
be kept for later use. Otherwise, nodes are deleted when the parent
node is closed or after each data, comment, CDATA, or directive node.</p>
<h3 class="function"><a id="mxmlSaveAllocString">mxmlSaveAllocString</a></h3>
<p class="description">Save an XML tree to an allocated string.</p>
<p class="code">
char *mxmlSaveAllocString(<a href="#mxml_node_t">mxml_node_t</a> *node, <a href="#mxml_save_cb_t">mxml_save_cb_t</a> cb);</p>
char *mxmlSaveAllocString(<a href="#mxml_node_t">mxml_node_t</a> *node, <a href="#mxml_save_cb_t">mxml_save_cb_t</a> save_cb, void *save_cbdata);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>node</th>
<td class="description">Node to write</td></tr>
<tr><th>cb</th>
<td class="description">Whitespace callback or <code>MXML_NO_CALLBACK</code></td></tr>
<tr><th>save_cb</th>
<td class="description">Whitespace callback function</td></tr>
<tr><th>save_cbdata</th>
<td class="description">Whitespace callback data</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">Allocated string or <code>NULL</code></p>
@ -2436,15 +2398,17 @@ element tags.</p>
<h3 class="function"><a id="mxmlSaveFd">mxmlSaveFd</a></h3>
<p class="description">Save an XML tree to a file descriptor.</p>
<p class="code">
bool mxmlSaveFd(<a href="#mxml_node_t">mxml_node_t</a> *node, int fd, <a href="#mxml_save_cb_t">mxml_save_cb_t</a> cb);</p>
bool mxmlSaveFd(<a href="#mxml_node_t">mxml_node_t</a> *node, int fd, <a href="#mxml_save_cb_t">mxml_save_cb_t</a> save_cb, void *save_cbdata);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>node</th>
<td class="description">Node to write</td></tr>
<tr><th>fd</th>
<td class="description">File descriptor to write to</td></tr>
<tr><th>cb</th>
<td class="description">Whitespace callback or <code>MXML_NO_CALLBACK</code></td></tr>
<tr><th>save_cb</th>
<td class="description">Whitespace callback function</td></tr>
<tr><th>save_cbdata</th>
<td class="description">Whitespace callback data</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on error.</p>
@ -2457,15 +2421,65 @@ element tags.</p>
<h3 class="function"><a id="mxmlSaveFile">mxmlSaveFile</a></h3>
<p class="description">Save an XML tree to a file.</p>
<p class="code">
bool mxmlSaveFile(<a href="#mxml_node_t">mxml_node_t</a> *node, FILE *fp, <a href="#mxml_save_cb_t">mxml_save_cb_t</a> cb);</p>
bool mxmlSaveFile(<a href="#mxml_node_t">mxml_node_t</a> *node, FILE *fp, <a href="#mxml_save_cb_t">mxml_save_cb_t</a> save_cb, void *save_cbdata);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>node</th>
<td class="description">Node to write</td></tr>
<tr><th>fp</th>
<td class="description">File to write to</td></tr>
<tr><th>cb</th>
<td class="description">Whitespace callback or <code>MXML_NO_CALLBACK</code></td></tr>
<tr><th>save_cb</th>
<td class="description">Whitespace callback function</td></tr>
<tr><th>save_cbdata</th>
<td class="description">Whitespace callback data</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on error.</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">The callback argument specifies a function that returns a whitespace
string or NULL before and after each element. If <code>MXML_NO_CALLBACK</code>
is specified, whitespace will only be added before <code>MXML_TYPE_TEXT</code> nodes
with leading whitespace and before attribute names inside opening
element tags.</p>
<h3 class="function"><a id="mxmlSaveFilename">mxmlSaveFilename</a></h3>
<p class="description">Save an XML tree to a file.</p>
<p class="code">
bool mxmlSaveFilename(<a href="#mxml_node_t">mxml_node_t</a> *node, const char *filename, <a href="#mxml_save_cb_t">mxml_save_cb_t</a> save_cb, void *save_cbdata);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>node</th>
<td class="description">Node to write</td></tr>
<tr><th>filename</th>
<td class="description">File to write to</td></tr>
<tr><th>save_cb</th>
<td class="description">Whitespace callback function</td></tr>
<tr><th>save_cbdata</th>
<td class="description">Whitespace callback data</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on error.</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">The callback argument specifies a function that returns a whitespace
string or NULL before and after each element. If <code>MXML_NO_CALLBACK</code>
is specified, whitespace will only be added before <code>MXML_TYPE_TEXT</code> nodes
with leading whitespace and before attribute names inside opening
element tags.</p>
<h3 class="function"><a id="mxmlSaveIO">mxmlSaveIO</a></h3>
<p class="description">Save an XML tree using a callback.</p>
<p class="code">
bool mxmlSaveIO(<a href="#mxml_node_t">mxml_node_t</a> *node, <a href="#mxml_write_cb_t">mxml_write_cb_t</a> write_cb, void *write_cbdata, <a href="#mxml_save_cb_t">mxml_save_cb_t</a> save_cb, void *save_cbdata);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>node</th>
<td class="description">Node to write</td></tr>
<tr><th>write_cb</th>
<td class="description">Write callback function</td></tr>
<tr><th>write_cbdata</th>
<td class="description">Write callback data</td></tr>
<tr><th>save_cb</th>
<td class="description">Whitespace callback function</td></tr>
<tr><th>save_cbdata</th>
<td class="description">Whitespace callback data</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description"><code>true</code> on success, <code>false</code> on error.</p>
@ -2478,7 +2492,7 @@ element tags.</p>
<h3 class="function"><a id="mxmlSaveString">mxmlSaveString</a></h3>
<p class="description">Save an XML node tree to a string.</p>
<p class="code">
size_t mxmlSaveString(<a href="#mxml_node_t">mxml_node_t</a> *node, char *buffer, size_t bufsize, <a href="#mxml_save_cb_t">mxml_save_cb_t</a> cb);</p>
size_t mxmlSaveString(<a href="#mxml_node_t">mxml_node_t</a> *node, char *buffer, size_t bufsize, <a href="#mxml_save_cb_t">mxml_save_cb_t</a> save_cb, void *save_cbdata);</p>
<h4 class="parameters">Parameters</h4>
<table class="list"><tbody>
<tr><th>node</th>
@ -2487,8 +2501,10 @@ size_t mxmlSaveString(<a href="#mxml_node_t">mxml_node_t</a> *node, char *buffer
<td class="description">String buffer</td></tr>
<tr><th>bufsize</th>
<td class="description">Size of string buffer</td></tr>
<tr><th>cb</th>
<td class="description">Whitespace callback or <code>MXML_NO_CALLBACK</code></td></tr>
<tr><th>save_cb</th>
<td class="description">Whitespace callback function</td></tr>
<tr><th>save_cbdata</th>
<td class="description">Whitespace callback function</td></tr>
</tbody></table>
<h4 class="returnvalue">Return Value</h4>
<p class="description">Size of string</p>
@ -2843,17 +2859,17 @@ typedef void (*mxml_custom_destroy_cb_t)(void *);
<h3 class="typedef"><a id="mxml_custom_load_cb_t">mxml_custom_load_cb_t</a></h3>
<p class="description">Custom data load callback function</p>
<p class="code">
typedef bool (*mxml_custom_load_cb_t)(<a href="#mxml_node_t">mxml_node_t</a> *, const char *);
typedef bool (*mxml_custom_load_cb_t)(<a href="#mxml_node_t">mxml_node_t</a> *node const char *s);
</p>
<h3 class="typedef"><a id="mxml_custom_save_cb_t">mxml_custom_save_cb_t</a></h3>
<p class="description">Custom data save callback function</p>
<p class="code">
typedef char *(*mxml_custom_save_cb_t)(<a href="#mxml_node_t">mxml_node_t</a> *);
typedef char *(*mxml_custom_save_cb_t)(<a href="#mxml_node_t">mxml_node_t</a> *node);
</p>
<h3 class="typedef"><a id="mxml_entity_cb_t">mxml_entity_cb_t</a></h3>
<p class="description">Entity callback function</p>
<p class="code">
typedef int (*mxml_entity_cb_t)(const char *);
typedef int (*mxml_entity_cb_t)(const char *name);
</p>
<h3 class="typedef"><a id="mxml_error_cb_t">mxml_error_cb_t</a></h3>
<p class="description">Error callback function</p>
@ -2868,22 +2884,27 @@ typedef struct _mxml_index_s mxml_index_t;
<h3 class="typedef"><a id="mxml_load_cb_t">mxml_load_cb_t</a></h3>
<p class="description">Load callback function</p>
<p class="code">
typedef <a href="#mxml_type_t">mxml_type_t</a> (*mxml_load_cb_t)(<a href="#mxml_node_t">mxml_node_t</a> *);
typedef <a href="#mxml_type_t">mxml_type_t</a> (*mxml_load_cb_t)(void *cbdata <a href="#mxml_node_t">mxml_node_t</a> *node);
</p>
<h3 class="typedef"><a id="mxml_node_t">mxml_node_t</a></h3>
<p class="description">An XML node.</p>
<p class="code">
typedef struct _mxml_node_s mxml_node_t;
</p>
<h3 class="typedef"><a id="mxml_read_cb_t">mxml_read_cb_t</a></h3>
<p class="description">Read callback function</p>
<p class="code">
typedef ssize_t (*mxml_read_cb_t)(void *cbdata void *buffer size_t bytes);
</p>
<h3 class="typedef"><a id="mxml_save_cb_t">mxml_save_cb_t</a></h3>
<p class="description">Save callback function</p>
<p class="code">
typedef const char *(*mxml_save_cb_t)(<a href="#mxml_node_t">mxml_node_t</a> *, int);
typedef const char *(*mxml_save_cb_t)(void *cbdata <a href="#mxml_node_t">mxml_node_t</a> *node <a href="#mxml_ws_t">mxml_ws_t</a> when);
</p>
<h3 class="typedef"><a id="mxml_sax_cb_t">mxml_sax_cb_t</a></h3>
<p class="description">SAX callback function</p>
<p class="code">
typedef bool (*mxml_sax_cb_t)(<a href="#mxml_node_t">mxml_node_t</a> *, mxml_sax_event_t, void *);
typedef bool (*mxml_sax_cb_t)(void *cbdata <a href="#mxml_node_t">mxml_node_t</a> *node <a href="#mxml_sax_event_t">mxml_sax_event_t</a> event);
</p>
<h3 class="typedef"><a id="mxml_sax_event_t">mxml_sax_event_t</a></h3>
<p class="description">SAX event type.</p>
@ -2895,6 +2916,16 @@ typedef enum <a href="#mxml_sax_event_e">mxml_sax_event_e</a> mxml_sax_event_t;
<p class="code">
typedef enum <a href="#mxml_type_e">mxml_type_e</a> mxml_type_t;
</p>
<h3 class="typedef"><a id="mxml_write_cb_t">mxml_write_cb_t</a></h3>
<p class="description">Write callback function</p>
<p class="code">
typedef ssize_t (*mxml_write_cb_t)(void *cbdata const void *buffer size_t bytes);
</p>
<h3 class="typedef"><a id="mxml_ws_t">mxml_ws_t</a></h3>
<p class="description">Whitespace periods</p>
<p class="code">
typedef enum <a href="#mxml_ws_e">mxml_ws_e</a> mxml_ws_t;
</p>
<h2 class="title"><a id="ENUMERATIONS">Constants</a></h2>
<h3 class="enumeration"><a id="mxml_sax_event_e">mxml_sax_event_e</a></h3>
<p class="description">SAX event type.</p>
@ -2924,6 +2955,15 @@ typedef enum <a href="#mxml_type_e">mxml_type_e</a> mxml_type_t;
<tr><th>MXML_TYPE_REAL </th><td class="description">Real value</td></tr>
<tr><th>MXML_TYPE_TEXT </th><td class="description">Text fragment</td></tr>
</tbody></table>
<h3 class="enumeration"><a id="mxml_ws_e">mxml_ws_e</a></h3>
<p class="description">Whitespace periods</p>
<h4 class="constants">Constants</h4>
<table class="list"><tbody>
<tr><th>MXML_WS_AFTER_CLOSE </th><td class="description">Callback for after close tag</td></tr>
<tr><th>MXML_WS_AFTER_OPEN </th><td class="description">Callback for after open tag</td></tr>
<tr><th>MXML_WS_BEFORE_CLOSE </th><td class="description">Callback for before close tag</td></tr>
<tr><th>MXML_WS_BEFORE_OPEN </th><td class="description">Callback for before open tag</td></tr>
</tbody></table>
</div>
</body>
</html>

@ -167,7 +167,7 @@ mxmlElementSetAttr(mxml_node_t *node, // I - Element node
{
if ((valuec = strdup(value)) == NULL)
{
mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
_mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
return;
}
}
@ -213,7 +213,7 @@ mxmlElementSetAttrf(mxml_node_t *node, // I - Element node
va_end(ap);
if ((value = strdup(buffer)) == NULL)
mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
_mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
else if (!mxml_set_attr(node, name, value))
free(value);
}
@ -250,7 +250,7 @@ mxml_set_attr(mxml_node_t *node, // I - Element node
if (!attr)
{
mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
_mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
return (false);
}
@ -259,7 +259,7 @@ mxml_set_attr(mxml_node_t *node, // I - Element node
if ((attr->name = strdup(name)) == NULL)
{
mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
_mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
return (false);
}

@ -33,7 +33,7 @@ mxmlEntityAddCallback(
}
else
{
mxml_error("Unable to add entity callback!");
_mxml_error("Unable to add entity callback!");
return (false);
}
@ -41,27 +41,25 @@ mxmlEntityAddCallback(
//
// 'mxmlEntityGetName()' - Get the name that corresponds to the character value.
//
// If val does not need to be represented by a named entity, @code NULL@ is returned.
// '_mxml_entity_string()' - Get the entity that corresponds to the character, if any.
//
const char * // O - Entity name or @code NULL@
mxmlEntityGetName(int val) // I - Character value
const char * // O - Entity or `NULL` for none
_mxml_entity_string(int ch) // I - Character
{
switch (val)
switch (ch)
{
case '&' :
return ("amp");
return ("&amp;");
case '<' :
return ("lt");
return ("&lt;");
case '>' :
return ("gt");
return ("&gt;");
case '\"' :
return ("quot");
return ("&quot;");
default :
return (NULL);

File diff suppressed because it is too large Load Diff

@ -136,12 +136,8 @@ mxmlGetElement(mxml_node_t *node) // I - Node to get
mxml_node_t * // O - First child or `NULL`
mxmlGetFirstChild(mxml_node_t *node) // I - Node to get
{
// Range check input...
if (!node || node->type != MXML_TYPE_ELEMENT)
return (NULL);
// Return the first child node...
return (node->child);
return (node ? node->child : NULL);
}
@ -179,12 +175,7 @@ mxmlGetInteger(mxml_node_t *node) // I - Node to get
mxml_node_t * // O - Last child or `NULL`
mxmlGetLastChild(mxml_node_t *node) // I - Node to get
{
// Range check input...
if (!node || node->type != MXML_TYPE_ELEMENT)
return (NULL);
// Return the last child node...
return (node->last_child);
return (node ? node->last_child : NULL);
}
@ -197,12 +188,7 @@ mxmlGetLastChild(mxml_node_t *node) // I - Node to get
mxml_node_t *
mxmlGetNextSibling(mxml_node_t *node) // I - Node to get
{
// Range check input...
if (!node)
return (NULL);
// Return the next sibling node...
return (node->next);
return (node ? node->next : NULL);
}
@ -239,12 +225,7 @@ mxmlGetOpaque(mxml_node_t *node) // I - Node to get
mxml_node_t * // O - Parent node or `NULL`
mxmlGetParent(mxml_node_t *node) // I - Node to get
{
// Range check input...
if (!node)
return (NULL);
// Return the parent node...
return (node->parent);
return (node ? node->parent : NULL);
}
@ -257,12 +238,7 @@ mxmlGetParent(mxml_node_t *node) // I - Node to get
mxml_node_t * // O - Previous node or `NULL`
mxmlGetPrevSibling(mxml_node_t *node) // I - Node to get
{
// Range check input...
if (!node)
return (NULL);
// Return the previous sibling node...
return (node->prev);
return (node ? node->prev : NULL);
}

@ -181,7 +181,7 @@ mxmlIndexFind(mxml_index_t *ind, // I - Index to search
// 'mxmlIndexGetCount()' - Get the number of nodes in an index.
//
int // I - Number of nodes in index
size_t // I - Number of nodes in index
mxmlIndexGetCount(mxml_index_t *ind) // I - Index of nodes
{
// Range check input...
@ -222,7 +222,7 @@ mxmlIndexNew(mxml_node_t *node, // I - XML node tree
// Create a new index...
if ((ind = calloc(1, sizeof(mxml_index_t))) == NULL)
{
mxml_error("Unable to allocate memory for index.");
_mxml_error("Unable to allocate memory for index.");
return (NULL);
}
@ -230,7 +230,7 @@ mxmlIndexNew(mxml_node_t *node, // I - XML node tree
{
if ((ind->attr = strdup(attr)) == NULL)
{
mxml_error("Unable to allocate memory for index attribute.");
_mxml_error("Unable to allocate memory for index attribute.");
free(ind);
return (NULL);
}
@ -253,7 +253,7 @@ mxmlIndexNew(mxml_node_t *node, // I - XML node tree
if (!temp)
{
// Unable to allocate memory for the index, so abort...
mxml_error("Unable to allocate memory for index nodes.");
_mxml_error("Unable to allocate memory for index nodes.");
mxmlIndexDelete(ind);
return (NULL);
}

@ -210,7 +210,7 @@ mxmlNewCDATA(mxml_node_t *parent, // I - Parent node or `MXML_NO_PARENT`
{
if ((node->value.cdata = strdup(data)) == NULL)
{
mxml_error("Unable to allocate memory for CDATA.");
_mxml_error("Unable to allocate memory for CDATA.");
mxmlDelete(node);
return (NULL);
}
@ -286,7 +286,7 @@ mxmlNewComment(mxml_node_t *parent, // I - Parent node or `MXML_NO_PARENT`
{
if ((node->value.comment = strdup(comment)) == NULL)
{
mxml_error("Unable to allocate memory for comment.");
_mxml_error("Unable to allocate memory for comment.");
mxmlDelete(node);
return (NULL);
}
@ -394,7 +394,7 @@ mxmlNewDeclaration(
{
if ((node->value.declaration = strdup(declaration)) == NULL)
{
mxml_error("Unable to allocate memory for declaration.");
_mxml_error("Unable to allocate memory for declaration.");
mxmlDelete(node);
return (NULL);
}
@ -471,7 +471,7 @@ mxmlNewDirective(mxml_node_t *parent, // I - Parent node or `MXML_NO_PARENT`
{
if ((node->value.directive = strdup(directive)) == NULL)
{
mxml_error("Unable to allocate memory for processing instruction.");
_mxml_error("Unable to allocate memory for processing instruction.");
mxmlDelete(node);
return (NULL);
}

@ -40,11 +40,11 @@
//
// 'mxml_error()' - Display an error message.
// '_mxml_error()' - Display an error message.
//
void
mxml_error(const char *format, // I - Printf-style format string
_mxml_error(const char *format, // I - Printf-style format string
...) // I - Additional arguments as needed
{
va_list ap; // Pointer to arguments
@ -70,58 +70,6 @@ mxml_error(const char *format, // I - Printf-style format string
}
//
// 'mxml_ignore_cb()' - Default callback for ignored values.
//
mxml_type_t // O - Node type
mxml_ignore_cb(mxml_node_t *node) // I - Current node
{
(void)node;
return (MXML_TYPE_IGNORE);
}
//
// 'mxml_integer_cb()' - Default callback for integer values.
//
mxml_type_t // O - Node type
mxml_integer_cb(mxml_node_t *node) // I - Current node
{
(void)node;
return (MXML_TYPE_INTEGER);
}
//
// 'mxml_opaque_cb()' - Default callback for opaque values.
//
mxml_type_t // O - Node type
mxml_opaque_cb(mxml_node_t *node) // I - Current node
{
(void)node;
return (MXML_TYPE_OPAQUE);
}
//
// 'mxml_real_cb()' - Default callback for real number values.
//
mxml_type_t // O - Node type
mxml_real_cb(mxml_node_t *node) // I - Current node
{
(void)node;
return (MXML_TYPE_REAL);
}
#ifdef HAVE_PTHREAD_H // POSIX threading
# include <pthread.h>

@ -109,6 +109,8 @@ typedef struct _mxml_global_s // Global, per-thread data
extern _mxml_global_t *_mxml_global(void);
extern int _mxml_entity_cb(const char *name);
extern const char *_mxml_entity_string(int ch);
extern void _mxml_error(const char *format, ...) MXML_FORMAT(1,2);
#endif // !MXML_PRIVATE_H

@ -31,12 +31,12 @@ mxmlSetCDATA(mxml_node_t *node, // I - Node to set
if (!node || node->type != MXML_TYPE_CDATA)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
else if (!data)
{
mxml_error("NULL string not allowed.");
_mxml_error("NULL string not allowed.");
return (false);
}
@ -49,7 +49,7 @@ mxmlSetCDATA(mxml_node_t *node, // I - Node to set
// Allocate the new value, free any old element value, and set the new value...
if ((s = strdup(data)) == NULL)
{
mxml_error("Unable to allocate memory for CDATA.");
_mxml_error("Unable to allocate memory for CDATA.");
return (false);
}
@ -80,12 +80,12 @@ mxmlSetCDATAf(mxml_node_t *node, // I - Node
if (!node || node->type != MXML_TYPE_CDATA)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
else if (!format)
{
mxml_error("NULL string not allowed.");
_mxml_error("NULL string not allowed.");
return (false);
}
@ -96,7 +96,7 @@ mxmlSetCDATAf(mxml_node_t *node, // I - Node
if ((s = strdup(buffer)) == NULL)
{
mxml_error("Unable to allocate memory for CDATA string.");
_mxml_error("Unable to allocate memory for CDATA string.");
return (false);
}
@ -124,12 +124,12 @@ mxmlSetComment(mxml_node_t *node, // I - Node
if (!node || node->type != MXML_TYPE_COMMENT)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
else if (!comment)
{
mxml_error("NULL comment not allowed.");
_mxml_error("NULL comment not allowed.");
return (false);
}
@ -139,7 +139,7 @@ mxmlSetComment(mxml_node_t *node, // I - Node
// Free any old string value and set the new value...
if ((s = strdup(comment)) == NULL)
{
mxml_error("Unable to allocate memory for comment string.");
_mxml_error("Unable to allocate memory for comment string.");
return (false);
}
@ -170,12 +170,12 @@ mxmlSetCommentf(mxml_node_t *node, // I - Node
if (!node || node->type != MXML_TYPE_COMMENT)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
else if (!format)
{
mxml_error("NULL string not allowed.");
_mxml_error("NULL string not allowed.");
return (false);
}
@ -186,7 +186,7 @@ mxmlSetCommentf(mxml_node_t *node, // I - Node
if ((s = strdup(buffer)) == NULL)
{
mxml_error("Unable to allocate memory for comment string.");
_mxml_error("Unable to allocate memory for comment string.");
return (false);
}
@ -215,7 +215,7 @@ mxmlSetCustom(
if (!node || node->type != MXML_TYPE_CUSTOM)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
@ -254,12 +254,12 @@ mxmlSetDeclaration(
if (!node || node->type != MXML_TYPE_DECLARATION)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
else if (!declaration)
{
mxml_error("NULL declaration not allowed.");
_mxml_error("NULL declaration not allowed.");
return (false);
}
@ -269,7 +269,7 @@ mxmlSetDeclaration(
// Free any old string value and set the new value...
if ((s = strdup(declaration)) == NULL)
{
mxml_error("Unable to allocate memory for declaration string.");
_mxml_error("Unable to allocate memory for declaration string.");
return (false);
}
@ -300,12 +300,12 @@ mxmlSetDeclarationf(mxml_node_t *node, // I - Node
if (!node || node->type != MXML_TYPE_COMMENT)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
else if (!format)
{
mxml_error("NULL string not allowed.");
_mxml_error("NULL string not allowed.");
return (false);
}
@ -316,7 +316,7 @@ mxmlSetDeclarationf(mxml_node_t *node, // I - Node
if ((s = strdup(buffer)) == NULL)
{
mxml_error("Unable to allocate memory for declaration string.");
_mxml_error("Unable to allocate memory for declaration string.");
return (false);
}
@ -344,12 +344,12 @@ mxmlSetDirective(mxml_node_t *node, // I - Node
if (!node || node->type != MXML_TYPE_DIRECTIVE)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
else if (!directive)
{
mxml_error("NULL directive not allowed.");
_mxml_error("NULL directive not allowed.");
return (false);
}
@ -359,7 +359,7 @@ mxmlSetDirective(mxml_node_t *node, // I - Node
// Free any old string value and set the new value...
if ((s = strdup(directive)) == NULL)
{
mxml_error("Unable to allocate memory for directive string.");
_mxml_error("Unable to allocate memory for directive string.");
return (false);
}
@ -390,12 +390,12 @@ mxmlSetDirectivef(mxml_node_t *node, // I - Node
if (!node || node->type != MXML_TYPE_DIRECTIVE)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
else if (!format)
{
mxml_error("NULL string not allowed.");
_mxml_error("NULL string not allowed.");
return (false);
}
@ -406,7 +406,7 @@ mxmlSetDirectivef(mxml_node_t *node, // I - Node
if ((s = strdup(buffer)) == NULL)
{
mxml_error("Unable to allocate memory for directive string.");
_mxml_error("Unable to allocate memory for directive string.");
return (false);
}
@ -433,12 +433,12 @@ mxmlSetElement(mxml_node_t *node, // I - Node to set
// Range check input...
if (!node || node->type != MXML_TYPE_ELEMENT)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
else if (!name)
{
mxml_error("NULL string not allowed.");
_mxml_error("NULL string not allowed.");
return (false);
}
@ -448,7 +448,7 @@ mxmlSetElement(mxml_node_t *node, // I - Node to set
// Free any old element value and set the new value...
if ((s = strdup(name)) == NULL)
{
mxml_error("Unable to allocate memory for element name.");
_mxml_error("Unable to allocate memory for element name.");
return (false);
}
@ -475,7 +475,7 @@ mxmlSetInteger(mxml_node_t *node, // I - Node to set
if (!node || node->type != MXML_TYPE_INTEGER)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
@ -505,12 +505,12 @@ mxmlSetOpaque(mxml_node_t *node, // I - Node to set
if (!node || node->type != MXML_TYPE_OPAQUE)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
else if (!opaque)
{
mxml_error("NULL string not allowed.");
_mxml_error("NULL string not allowed.");
return (false);
}
@ -520,7 +520,7 @@ mxmlSetOpaque(mxml_node_t *node, // I - Node to set
// Free any old opaque value and set the new value...
if ((s = strdup(opaque)) == NULL)
{
mxml_error("Unable to allocate memory for opaque string.");
_mxml_error("Unable to allocate memory for opaque string.");
return (false);
}
@ -553,12 +553,12 @@ mxmlSetOpaquef(mxml_node_t *node, // I - Node to set
if (!node || node->type != MXML_TYPE_OPAQUE)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
else if (!format)
{
mxml_error("NULL string not allowed.");
_mxml_error("NULL string not allowed.");
return (false);
}
@ -569,7 +569,7 @@ mxmlSetOpaquef(mxml_node_t *node, // I - Node to set
if ((s = strdup(buffer)) == NULL)
{
mxml_error("Unable to allocate memory for opaque string.");
_mxml_error("Unable to allocate memory for opaque string.");
return (false);
}
@ -599,7 +599,7 @@ mxmlSetReal(mxml_node_t *node, // I - Node to set
if (!node || node->type != MXML_TYPE_REAL)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
@ -630,12 +630,12 @@ mxmlSetText(mxml_node_t *node, // I - Node to set
if (!node || node->type != MXML_TYPE_TEXT)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
else if (!string)
{
mxml_error("NULL string not allowed.");
_mxml_error("NULL string not allowed.");
return (false);
}
@ -648,7 +648,7 @@ mxmlSetText(mxml_node_t *node, // I - Node to set
// Free any old string value and set the new value...
if ((s = strdup(string)) == NULL)
{
mxml_error("Unable to allocate memory for text string.");
_mxml_error("Unable to allocate memory for text string.");
return (false);
}
@ -684,12 +684,12 @@ mxmlSetTextf(mxml_node_t *node, // I - Node to set
if (!node || node->type != MXML_TYPE_TEXT)
{
mxml_error("Wrong node type.");
_mxml_error("Wrong node type.");
return (false);
}
else if (!format)
{
mxml_error("NULL string not allowed.");
_mxml_error("NULL string not allowed.");
return (false);
}
@ -700,7 +700,7 @@ mxmlSetTextf(mxml_node_t *node, // I - Node to set
if ((s = strdup(buffer)) == NULL)
{
mxml_error("Unable to allocate memory for text string.");
_mxml_error("Unable to allocate memory for text string.");
return (false);
}

@ -37,28 +37,10 @@ extern "C" {
# define MXML_TAB 8 // Tabs every N columns
# define MXML_NO_CALLBACK 0 // Don't use a type callback
# define MXML_INTEGER_CALLBACK mxml_integer_cb
// Treat all data as integers
# define MXML_OPAQUE_CALLBACK mxml_opaque_cb
// Treat all data as opaque
# define MXML_REAL_CALLBACK mxml_real_cb
// Treat all data as real numbers
# define MXML_TEXT_CALLBACK 0 // Treat all data as text
# define MXML_IGNORE_CALLBACK mxml_ignore_cb
// Ignore all non-element content
# define MXML_NO_PARENT 0 // No parent for the node
# define MXML_DESCEND 1 // Descend when finding/walking
# define MXML_NO_DESCEND 0 // Don't descend when finding/walking
# define MXML_DESCEND_FIRST -1 // Descend for first find
# define MXML_WS_BEFORE_OPEN 0 // Callback for before open tag
# define MXML_WS_AFTER_OPEN 1 // Callback for after open tag
# define MXML_WS_BEFORE_CLOSE 2 // Callback for before close tag
# define MXML_WS_AFTER_CLOSE 3 // Callback for after close tag
# define MXML_ADD_BEFORE 0 // Add node before specified node
# define MXML_ADD_AFTER 1 // Add node after specified node
# define MXML_ADD_TO_PARENT NULL // Add node relative to parent
@ -94,6 +76,14 @@ typedef enum mxml_type_e // The XML node type.
MXML_TYPE_CUSTOM // Custom data
} mxml_type_t;
typedef enum mxml_ws_e // Whitespace periods
{
MXML_WS_BEFORE_OPEN, // Callback for before open tag
MXML_WS_AFTER_OPEN, // Callback for after open tag
MXML_WS_BEFORE_CLOSE, // Callback for before close tag
MXML_WS_AFTER_CLOSE, // Callback for after close tag
} mxml_ws_t;
typedef void (*mxml_custom_destroy_cb_t)(void *);
// Custom data destructor
@ -105,22 +95,28 @@ typedef struct _mxml_node_s mxml_node_t;// An XML node.
typedef struct _mxml_index_s mxml_index_t;
// An XML node index.
typedef bool (*mxml_custom_load_cb_t)(mxml_node_t *, const char *);
typedef bool (*mxml_custom_load_cb_t)(mxml_node_t *node, const char *s);
// Custom data load callback function
typedef char *(*mxml_custom_save_cb_t)(mxml_node_t *);
typedef char *(*mxml_custom_save_cb_t)(mxml_node_t *node);
// Custom data save callback function
typedef int (*mxml_entity_cb_t)(const char *);
typedef int (*mxml_entity_cb_t)(const char *name);
// Entity callback function
typedef mxml_type_t (*mxml_load_cb_t)(mxml_node_t *);
typedef mxml_type_t (*mxml_load_cb_t)(void *cbdata, mxml_node_t *node);
// Load callback function
typedef const char *(*mxml_save_cb_t)(mxml_node_t *, int);
typedef ssize_t (*mxml_read_cb_t)(void *cbdata, void *buffer, size_t bytes);
// Read callback function
typedef const char *(*mxml_save_cb_t)(void *cbdata, mxml_node_t *node, mxml_ws_t when);
// Save callback function
typedef bool (*mxml_sax_cb_t)(mxml_node_t *, mxml_sax_event_t, void *);
typedef ssize_t (*mxml_write_cb_t)(void *cbdata, const void *buffer, size_t bytes);
// Write callback function
typedef bool (*mxml_sax_cb_t)(void *cbdata, mxml_node_t *node, mxml_sax_event_t event);
// SAX callback function
@ -129,7 +125,9 @@ typedef bool (*mxml_sax_cb_t)(mxml_node_t *, mxml_sax_event_t, void *);
//
extern void mxmlAdd(mxml_node_t *parent, int where, mxml_node_t *child, mxml_node_t *node);
extern void mxmlDelete(mxml_node_t *node);
extern void mxmlElementDeleteAttr(mxml_node_t *node, const char *name);
extern const char *mxmlElementGetAttr(mxml_node_t *node, const char *name);
extern const char *mxmlElementGetAttrByIndex(mxml_node_t *node, int idx, const char **name);
@ -137,13 +135,17 @@ extern size_t mxmlElementGetAttrCount(mxml_node_t *node);
extern void mxmlElementSetAttr(mxml_node_t *node, const char *name, const char *value);
extern void mxmlElementSetAttrf(mxml_node_t *node, const char *name, const char *format, ...) MXML_FORMAT(3,4);
extern bool mxmlEntityAddCallback(mxml_entity_cb_t cb);
extern const char *mxmlEntityGetName(int val);
extern int mxmlEntityGetValue(const char *name);
extern void mxmlEntityRemoveCallback(mxml_entity_cb_t cb);
extern mxml_node_t *mxmlFindElement(mxml_node_t *node, mxml_node_t *top, const char *element, const char *attr, const char *value, int descend);
extern mxml_node_t *mxmlFindPath(mxml_node_t *node, const char *path);
extern const char *mxmlGetCDATA(mxml_node_t *node);
extern const char *mxmlGetComment(mxml_node_t *node);
extern const void *mxmlGetCustom(mxml_node_t *node);
extern const char *mxmlGetDeclaration(mxml_node_t *node);
extern const char *mxmlGetDirective(mxml_node_t *node);
extern const char *mxmlGetElement(mxml_node_t *node);
extern mxml_node_t *mxmlGetFirstChild(mxml_node_t *node);
extern long mxmlGetInteger(mxml_node_t *node);
@ -157,14 +159,20 @@ extern size_t mxmlGetRefCount(mxml_node_t *node);
extern const char *mxmlGetText(mxml_node_t *node, bool *whitespace);
extern mxml_type_t mxmlGetType(mxml_node_t *node);
extern void *mxmlGetUserData(mxml_node_t *node);
extern void mxmlIndexDelete(mxml_index_t *ind);
extern mxml_node_t *mxmlIndexEnum(mxml_index_t *ind);
extern mxml_node_t *mxmlIndexFind(mxml_index_t *ind, const char *element, const char *value);
extern int mxmlIndexGetCount(mxml_index_t *ind);
extern size_t mxmlIndexGetCount(mxml_index_t *ind);
extern mxml_index_t *mxmlIndexNew(mxml_node_t *node, const char *element, const char *attr);
extern mxml_node_t *mxmlIndexReset(mxml_index_t *ind);
extern mxml_node_t *mxmlLoadFd(mxml_node_t *top, int fd, mxml_load_cb_t cb); extern mxml_node_t *mxmlLoadFile(mxml_node_t *top, FILE *fp, mxml_load_cb_t cb);
extern mxml_node_t *mxmlLoadString(mxml_node_t *top, const char *s, mxml_load_cb_t cb);
extern mxml_node_t *mxmlLoadFd(mxml_node_t *top, int fd, mxml_load_cb_t load_cb, void *load_cbdata, mxml_sax_cb_t sax_cb, void *sax_cbdata);
extern mxml_node_t *mxmlLoadFile(mxml_node_t *top, FILE *fp, mxml_load_cb_t load_cb, void *load_cbdata, mxml_sax_cb_t sax_cb, void *sax_cbdata);
extern mxml_node_t *mxmlLoadFilename(mxml_node_t *top, const char *filename, mxml_load_cb_t load_cb, void *load_cbdata, mxml_sax_cb_t sax_cb, void *sax_cbdata);
extern mxml_node_t *mxmlLoadIO(mxml_node_t *top, mxml_read_cb_t read_cb, void *read_cbdata, mxml_load_cb_t load_cb, void *load_cbdata, mxml_sax_cb_t sax_cb, void *sax_cbdata);
extern mxml_node_t *mxmlLoadString(mxml_node_t *top, const char *s, mxml_load_cb_t load_cb, void *load_cbdata, mxml_sax_cb_t sax_cb, void *sax_cbdata);
extern mxml_node_t *mxmlNewCDATA(mxml_node_t *parent, const char *string);
extern mxml_node_t *mxmlNewCDATAf(mxml_node_t *parent, const char *format, ...) MXML_FORMAT(2,3);
extern mxml_node_t *mxmlNewComment(mxml_node_t *parent, const char *comment);
@ -182,16 +190,17 @@ extern mxml_node_t *mxmlNewReal(mxml_node_t *parent, double real);
extern mxml_node_t *mxmlNewText(mxml_node_t *parent, bool whitespace, const char *string);
extern mxml_node_t *mxmlNewTextf(mxml_node_t *parent, bool whitespace, const char *format, ...) MXML_FORMAT(3,4);
extern mxml_node_t *mxmlNewXML(const char *version);
extern int mxmlRelease(mxml_node_t *node);
extern void mxmlRemove(mxml_node_t *node);
extern int mxmlRetain(mxml_node_t *node);
extern char *mxmlSaveAllocString(mxml_node_t *node, mxml_save_cb_t cb);
extern bool mxmlSaveFd(mxml_node_t *node, int fd, mxml_save_cb_t cb);
extern bool mxmlSaveFile(mxml_node_t *node, FILE *fp, mxml_save_cb_t cb);
extern size_t mxmlSaveString(mxml_node_t *node, char *buffer, size_t bufsize, mxml_save_cb_t cb);
extern mxml_node_t *mxmlSAXLoadFd(mxml_node_t *top, int fd, mxml_load_cb_t cb, mxml_sax_cb_t sax, void *sax_data);
extern mxml_node_t *mxmlSAXLoadFile(mxml_node_t *top, FILE *fp, mxml_load_cb_t cb, mxml_sax_cb_t sax, void *sax_data);
extern mxml_node_t *mxmlSAXLoadString(mxml_node_t *top, const char *s, mxml_load_cb_t cb, mxml_sax_cb_t sax, void *sax_data);
extern char *mxmlSaveAllocString(mxml_node_t *node, mxml_save_cb_t save_cb, void *save_cbdata);
extern bool mxmlSaveFd(mxml_node_t *node, int fd, mxml_save_cb_t save_cb, void *save_cbdata);
extern bool mxmlSaveFile(mxml_node_t *node, FILE *fp, mxml_save_cb_t save_cb, void *save_cbdata);
extern bool mxmlSaveFilename(mxml_node_t *node, const char *filename, mxml_save_cb_t save_cb, void *save_cbdata);
extern bool mxmlSaveIO(mxml_node_t *node, mxml_write_cb_t write_cb, void *write_cbdata, mxml_save_cb_t save_cb, void *save_cbdata);
extern size_t mxmlSaveString(mxml_node_t *node, char *buffer, size_t bufsize, mxml_save_cb_t save_cb, void *save_cbdata);
extern bool mxmlSetCDATA(mxml_node_t *node, const char *data);
extern bool mxmlSetCDATAf(mxml_node_t *node, const char *format, ...) MXML_FORMAT(2,3);
extern bool mxmlSetComment(mxml_node_t *node, const char *comment);
@ -212,21 +221,11 @@ extern bool mxmlSetText(mxml_node_t *node, bool whitespace, const char *string)
extern bool mxmlSetTextf(mxml_node_t *node, bool whitespace, const char *format, ...) MXML_FORMAT(3,4);
extern bool mxmlSetUserData(mxml_node_t *node, void *data);
extern void mxmlSetWrapMargin(int column);
extern mxml_node_t *mxmlWalkNext(mxml_node_t *node, mxml_node_t *top, int descend);
extern mxml_node_t *mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top, int descend);
//
// Semi-private functions...
//
extern void mxml_error(const char *format, ...) MXML_FORMAT(1,2);
extern mxml_type_t mxml_ignore_cb(mxml_node_t *node);
extern mxml_type_t mxml_integer_cb(mxml_node_t *node);
extern mxml_type_t mxml_opaque_cb(mxml_node_t *node);
extern mxml_type_t mxml_real_cb(mxml_node_t *node);
# ifdef __cplusplus
}
# endif // __cplusplus

@ -14,7 +14,7 @@
// information.
//
#include "mxml-private.h"
#include "mxml.h"
#ifndef _WIN32
# include <unistd.h>
#endif // !_WIN32
@ -35,9 +35,9 @@ int event_counts[7];
// Local functions...
//
bool sax_cb(mxml_node_t *node, mxml_sax_event_t event, void *data);
mxml_type_t type_cb(mxml_node_t *node);
const char *whitespace_cb(mxml_node_t *node, int where);
bool sax_cb(void *cbdata, mxml_node_t *node, mxml_sax_event_t event);
mxml_type_t type_cb(void *cbdata, mxml_node_t *node);
const char *whitespace_cb(void *cbdata, mxml_node_t *node, mxml_ws_t where);
//
@ -55,14 +55,22 @@ main(int argc, // I - Number of command-line args
*tree, // Element tree
*node; // Node which should be in test.xml
mxml_index_t *ind; // XML index
mxml_type_t type; // Node type
char buffer[16384]; // Save string
const char *text; // Text string
bool whitespace; // Whitespace before text string
static const char *types[] = // Strings for node types
{
"MXML_TYPE_CDATA",
"MXML_TYPE_COMMENT",
"MXML_TYPE_DECLARATION",
"MXML_TYPE_DIRECTIVE",
"MXML_TYPE_ELEMENT",
"MXML_TYPE_INTEGER",
"MXML_TYPE_OPAQUE",
"MXML_TYPE_REAL",
"MXML_TYPE_TEXT"
"MXML_TYPE_TEXT",
"MXML_TYPE_CUSTOM"
};
@ -83,16 +91,16 @@ main(int argc, // I - Number of command-line args
return (1);
}
if (tree->type != MXML_TYPE_ELEMENT)
if (mxmlGetType(tree) != MXML_TYPE_ELEMENT)
{
fprintf(stderr, "ERROR: Parent has type %s (%d), expected MXML_TYPE_ELEMENT.\n", tree->type < MXML_TYPE_ELEMENT || tree->type > MXML_TYPE_TEXT ? "UNKNOWN" : types[tree->type], tree->type);
fprintf(stderr, "ERROR: Parent has type %d(%s), expected MXML_TYPE_ELEMENT.\n", mxmlGetType(tree), types[mxmlGetType(tree)]);
mxmlDelete(tree);
return (1);
}
if (strcmp(tree->value.element.name, "element"))
if (strcmp(mxmlGetElement(tree), "element"))
{
fprintf(stderr, "ERROR: Parent value is \"%s\", expected \"element\".\n", tree->value.element.name);
fprintf(stderr, "ERROR: Parent value is \"%s\", expected \"element\".\n", mxmlGetElement(tree));
mxmlDelete(tree);
return (1);
}
@ -102,11 +110,19 @@ main(int argc, // I - Number of command-line args
mxmlNewReal(tree, 123.4);
mxmlNewText(tree, 1, "text");
mxmlLoadString(tree, "<group type='string'>string string string</group>", MXML_NO_CALLBACK);
mxmlLoadString(tree, "<group type='integer'>1 2 3</group>", MXML_INTEGER_CALLBACK);
mxmlLoadString(tree, "<group type='real'>1.0 2.0 3.0</group>", MXML_REAL_CALLBACK);
mxmlLoadString(tree, "<group>opaque opaque opaque</group>", MXML_OPAQUE_CALLBACK);
mxmlLoadString(tree, "<foo><bar><one><two>value<two>value2</two></two></one></bar></foo>", MXML_OPAQUE_CALLBACK);
type = MXML_TYPE_TEXT;
mxmlLoadString(tree, "<group type='string'>string string string</group>", /*load_cb*/NULL, /*load_cbdata*/&type, /*sax_cb*/NULL, /*sax_cbdata*/NULL);
type = MXML_TYPE_INTEGER;
mxmlLoadString(tree, "<group type='integer'>1 2 3</group>", /*load_cb*/NULL, /*load_cbdata*/&type, /*sax_cb*/NULL, /*sax_cbdata*/NULL);
type = MXML_TYPE_REAL;
mxmlLoadString(tree, "<group type='real'>1.0 2.0 3.0</group>", /*load_cb*/NULL, /*load_cbdata*/&type, /*sax_cb*/NULL, /*sax_cbdata*/NULL);
type = MXML_TYPE_OPAQUE;
mxmlLoadString(tree, "<group>opaque opaque opaque</group>", /*load_cb*/NULL, /*load_cbdata*/&type, /*sax_cb*/NULL, /*sax_cbdata*/NULL);
mxmlLoadString(tree, "<foo><bar><one><two>value<two>value2</two></two></one></bar></foo>", /*load_cb*/NULL, /*load_cbdata*/&type, /*sax_cb*/NULL, /*sax_cbdata*/NULL);
mxmlNewCDATA(tree, "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n");
mxmlNewCDATA(tree,
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n"
@ -123,7 +139,7 @@ main(int argc, // I - Number of command-line args
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n");
node = tree->child;
node = mxmlGetFirstChild(tree);
if (!node)
{
@ -132,21 +148,21 @@ main(int argc, // I - Number of command-line args
return (1);
}
if (node->type != MXML_TYPE_INTEGER)
if (mxmlGetType(node) != MXML_TYPE_INTEGER)
{
fprintf(stderr, "ERROR: First child has type %s (%d), expected MXML_TYPE_INTEGER.\n", node->type < MXML_TYPE_ELEMENT || node->type > MXML_TYPE_TEXT ? "UNKNOWN" : types[node->type], node->type);
fprintf(stderr, "ERROR: First child has type %d(%s), expected MXML_TYPE_INTEGER.\n", mxmlGetType(node), types[mxmlGetType(node)]);
mxmlDelete(tree);
return (1);
}
if (node->value.integer != 123)
if (mxmlGetInteger(node) != 123)
{
fprintf(stderr, "ERROR: First child value is %ld, expected 123.\n", node->value.integer);
fprintf(stderr, "ERROR: First child value is %ld, expected 123.\n", mxmlGetInteger(node));
mxmlDelete(tree);
return (1);
}
node = node->next;
node = mxmlGetNextSibling(node);
if (!node)
{
@ -155,21 +171,21 @@ main(int argc, // I - Number of command-line args
return (1);
}
if (node->type != MXML_TYPE_OPAQUE)
if (mxmlGetType(node) != MXML_TYPE_OPAQUE)
{
fprintf(stderr, "ERROR: Second child has type %s (%d), expected MXML_TYPE_OPAQUE.\n", node->type < MXML_TYPE_ELEMENT || node->type > MXML_TYPE_TEXT ? "UNKNOWN" : types[node->type], node->type);
fprintf(stderr, "ERROR: Second child has type %s (%d), expected MXML_TYPE_OPAQUE.\n", mxmlGetType(node) < MXML_TYPE_ELEMENT || mxmlGetType(node) > MXML_TYPE_TEXT ? "UNKNOWN" : types[mxmlGetType(node)], mxmlGetType(node));
mxmlDelete(tree);
return (1);
}
if (!node->value.opaque || strcmp(node->value.opaque, "opaque"))
if (!mxmlGetOpaque(node) || strcmp(mxmlGetOpaque(node), "opaque"))
{
fprintf(stderr, "ERROR: Second child value is \"%s\", expected \"opaque\".\n", node->value.opaque ? node->value.opaque : "(null)");
fprintf(stderr, "ERROR: Second child value is \"%s\", expected \"opaque\".\n", mxmlGetOpaque(node) ? mxmlGetOpaque(node) : "(null)");
mxmlDelete(tree);
return (1);
}
node = node->next;
node = mxmlGetNextSibling(node);
if (!node)
{
@ -178,21 +194,21 @@ main(int argc, // I - Number of command-line args
return (1);
}
if (node->type != MXML_TYPE_REAL)
if (mxmlGetType(node) != MXML_TYPE_REAL)
{
fprintf(stderr, "ERROR: Third child has type %s (%d), expected MXML_TYPE_REAL.\n", node->type < MXML_TYPE_ELEMENT || node->type > MXML_TYPE_TEXT ? "UNKNOWN" : types[node->type], node->type);
fprintf(stderr, "ERROR: Third child has type %s (%d), expected MXML_TYPE_REAL.\n", mxmlGetType(node) < MXML_TYPE_ELEMENT || mxmlGetType(node) > MXML_TYPE_TEXT ? "UNKNOWN" : types[mxmlGetType(node)], mxmlGetType(node));
mxmlDelete(tree);
return (1);
}
if (node->value.real != 123.4)
if (mxmlGetReal(node) != 123.4)
{
fprintf(stderr, "ERROR: Third child value is %f, expected 123.4.\n", node->value.real);
fprintf(stderr, "ERROR: Third child value is %f, expected 123.4.\n", mxmlGetReal(node));
mxmlDelete(tree);
return (1);
}
node = node->next;
node = mxmlGetNextSibling(node);
if (!node)
{
@ -201,23 +217,25 @@ main(int argc, // I - Number of command-line args
return (1);
}
if (node->type != MXML_TYPE_TEXT)
if (mxmlGetType(node) != MXML_TYPE_TEXT)
{
fprintf(stderr, "ERROR: Fourth child has type %s (%d), expected MXML_TYPE_TEXT.\n", node->type < MXML_TYPE_ELEMENT || node->type > MXML_TYPE_TEXT ? "UNKNOWN" : types[node->type], node->type);
fprintf(stderr, "ERROR: Fourth child has type %s (%d), expected MXML_TYPE_TEXT.\n", mxmlGetType(node) < MXML_TYPE_ELEMENT || mxmlGetType(node) > MXML_TYPE_TEXT ? "UNKNOWN" : types[mxmlGetType(node)], mxmlGetType(node));
mxmlDelete(tree);
return (1);
}
if (!node->value.text.whitespace || !node->value.text.string || strcmp(node->value.text.string, "text"))
text = mxmlGetText(node, &whitespace);
if (!whitespace || !text || strcmp(text, "text"))
{
fprintf(stderr, "ERROR: Fourth child value is %d,\"%s\", expected 1,\"text\".\n", node->value.text.whitespace, node->value.text.string ? node->value.text.string : "(null)");
fprintf(stderr, "ERROR: Fourth child value is %s,\"%s\", expected true,\"text\".\n", whitespace ? "true" : "false", text);
mxmlDelete(tree);
return (1);
}
for (i = 0; i < 4; i ++)
{
node = node->next;
node = mxmlGetNextSibling(node);
if (!node)
{
@ -226,9 +244,9 @@ main(int argc, // I - Number of command-line args
return (1);
}
if (node->type != MXML_TYPE_ELEMENT)
if (mxmlGetType(node) != MXML_TYPE_ELEMENT)
{
fprintf(stderr, "ERROR: Group child #%d has type %s (%d), expected MXML_TYPE_ELEMENT.\n", i + 1, node->type < MXML_TYPE_ELEMENT || node->type > MXML_TYPE_TEXT ? "UNKNOWN" : types[node->type], node->type);
fprintf(stderr, "ERROR: Group child #%d has type %d(%s), expected MXML_TYPE_ELEMENT.\n", i + 1, mxmlGetType(node), types[mxmlGetType(node)]);
mxmlDelete(tree);
return (1);
}
@ -242,9 +260,9 @@ main(int argc, // I - Number of command-line args
mxmlDelete(tree);
return (1);
}
else if (node->type != MXML_TYPE_OPAQUE || strcmp(node->value.opaque, "value"))
else if (mxmlGetType(node) != MXML_TYPE_OPAQUE || strcmp(mxmlGetOpaque(node), "value"))
{
fputs("ERROR: Bad value for \"*/two\".\n", stderr);
fprintf(stderr, "ERROR: Bad value for \"*/two\" - node=%p(%s), opaque=\"%s\"\n", node, types[mxmlGetType(node)], mxmlGetOpaque(node));
mxmlDelete(tree);
return (1);
}
@ -256,7 +274,7 @@ main(int argc, // I - Number of command-line args
mxmlDelete(tree);
return (1);
}
else if (node->type != MXML_TYPE_OPAQUE || strcmp(node->value.opaque, "value"))
else if (mxmlGetType(node) != MXML_TYPE_OPAQUE || strcmp(mxmlGetOpaque(node), "value"))
{
fputs("ERROR: Bad value for \"foo/*/two\".\n", stderr);
mxmlDelete(tree);
@ -270,7 +288,7 @@ main(int argc, // I - Number of command-line args
mxmlDelete(tree);
return (1);
}
else if (node->type != MXML_TYPE_OPAQUE || strcmp(node->value.opaque, "value"))
else if (mxmlGetType(node) != MXML_TYPE_OPAQUE || strcmp(mxmlGetOpaque(node), "value"))
{
fputs("ERROR: Bad value for \"foo/bar/one/two\".\n", stderr);
mxmlDelete(tree);
@ -286,9 +304,9 @@ main(int argc, // I - Number of command-line args
return (1);
}
if (ind->num_nodes != 10)
if (mxmlIndexGetCount(ind) != 10)
{
fprintf(stderr, "ERROR: Index of all nodes contains %lu nodes; expected 10.\n", (unsigned long)ind->num_nodes);
fprintf(stderr, "ERROR: Index of all nodes contains %lu nodes; expected 10.\n", (unsigned long)mxmlIndexGetCount(ind));
mxmlIndexDelete(ind);
mxmlDelete(tree);
return (1);
@ -313,9 +331,9 @@ main(int argc, // I - Number of command-line args
return (1);
}
if (ind->num_nodes != 4)
if (mxmlIndexGetCount(ind) != 4)
{
fprintf(stderr, "ERROR: Index of groups contains %lu nodes; expected 4.\n", (unsigned long)ind->num_nodes);
fprintf(stderr, "ERROR: Index of groups contains %lu nodes; expected 4.\n", (unsigned long)mxmlIndexGetCount(ind));
mxmlIndexDelete(ind);
mxmlDelete(tree);
return (1);
@ -340,9 +358,9 @@ main(int argc, // I - Number of command-line args
return (1);
}
if (ind->num_nodes != 3)
if (mxmlIndexGetCount(ind) != 3)
{
fprintf(stderr, "ERROR: Index of type attributes contains %lu nodes; expected 3.\n", (unsigned long)ind->num_nodes);
fprintf(stderr, "ERROR: Index of type attributes contains %lu nodes; expected 3.\n", (unsigned long)mxmlIndexGetCount(ind));
mxmlIndexDelete(ind);
mxmlDelete(tree);
return (1);
@ -367,9 +385,9 @@ main(int argc, // I - Number of command-line args
return (1);
}
if (ind->num_nodes != 3)
if (mxmlIndexGetCount(ind) != 3)
{
fprintf(stderr, "ERROR: Index of elements and attributes contains %lu nodes; expected 3.\n", (unsigned long)ind->num_nodes);
fprintf(stderr, "ERROR: Index of elements and attributes contains %lu nodes; expected 3.\n", (unsigned long)mxmlIndexGetCount(ind));
mxmlIndexDelete(ind);
mxmlDelete(tree);
return (1);
@ -389,9 +407,9 @@ main(int argc, // I - Number of command-line args
// Check the mxmlDelete() works properly...
for (i = 0; i < 12; i ++)
{
if (tree->child)
if (mxmlGetFirstChild(tree))
{
mxmlDelete(tree->child);
mxmlDelete(mxmlGetFirstChild(tree));
}
else
{
@ -401,13 +419,13 @@ main(int argc, // I - Number of command-line args
}
}
if (tree->child)
if (mxmlGetFirstChild(tree))
{
fputs("ERROR: Child pointer not NULL after deleting all children.\n", stderr);
return (1);
}
if (tree->last_child)
if (mxmlGetLastChild(tree))
{
fputs("ERROR: Last child pointer not NULL after deleting all children.\n", stderr);
return (1);
@ -417,21 +435,9 @@ main(int argc, // I - Number of command-line args
// Open the file/string using the default (MXML_NO_CALLBACK) callback...
if (argv[1][0] == '<')
{
xml = mxmlLoadString(NULL, argv[1], MXML_NO_CALLBACK);
}
else if ((fp = fopen(argv[1], "rb")) == NULL)
{
perror(argv[1]);
return (1);
}
xml = mxmlLoadString(/*top*/NULL, argv[1], /*load_cb*/NULL, /*load_cbdata*/NULL, /*sax_cb*/NULL, /*sax_cbdata*/NULL);
else
{
// Read the file...
xml = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
fclose(fp);
}
xml = mxmlLoadFilename(/*top*/NULL, argv[1], /*load_cb*/NULL, /*load_cbdata*/NULL, /*sax_cb*/NULL, /*sax_cbdata*/NULL);
if (!xml)
{
@ -441,8 +447,6 @@ main(int argc, // I - Number of command-line args
if (!strcmp(argv[1], "test.xml"))
{
const char *text; // Text value
// Verify that mxmlFindElement() and indirectly mxmlWalkNext() work properly...
if ((node = mxmlFindPath(xml, "group/option/keyword")) == NULL)
{
@ -451,10 +455,10 @@ main(int argc, // I - Number of command-line args
return (1);
}
if (node->type != MXML_TYPE_TEXT)
if (mxmlGetType(node) != MXML_TYPE_TEXT)
{
fputs("No child node of group/option/keyword.\n", stderr);
mxmlSaveFile(xml, stderr, MXML_NO_CALLBACK);
mxmlSaveFile(xml, stderr, /*save_cb*/NULL, /*save_cbdata*/NULL);
mxmlDelete(xml);
return (1);
}
@ -471,21 +475,9 @@ main(int argc, // I - Number of command-line args
// Open the file...
if (argv[1][0] == '<')
{
xml = mxmlLoadString(NULL, argv[1], type_cb);
}
else if ((fp = fopen(argv[1], "rb")) == NULL)
{
perror(argv[1]);
return (1);
}
xml = mxmlLoadString(/*top*/NULL, argv[1], /*load_cb*/type_cb, /*load_cbdata*/NULL, /*sax_cb*/NULL, /*sax_cbdata*/NULL);
else
{
// Read the file...
xml = mxmlLoadFile(NULL, fp, type_cb);
fclose(fp);
}
xml = mxmlLoadFilename(/*top*/NULL, argv[1], /*load_cb*/type_cb, /*load_cbdata*/NULL, /*sax_cb*/NULL, /*sax_cbdata*/NULL);
if (!xml)
{
@ -512,10 +504,10 @@ main(int argc, // I - Number of command-line args
}
// Print the XML tree...
mxmlSaveFile(xml, stdout, whitespace_cb);
mxmlSaveFile(xml, stdout, whitespace_cb, /*save_cbdata*/NULL);
// Save the XML tree to a string and print it...
if (mxmlSaveString(xml, buffer, sizeof(buffer), whitespace_cb) > 0)
if (mxmlSaveString(xml, buffer, sizeof(buffer), whitespace_cb, /*save_cbdata*/NULL) > 0)
{
if (argc == 3)
{
@ -539,7 +531,7 @@ main(int argc, // I - Number of command-line args
}
// Read the file...
xml = mxmlLoadFd(NULL, fd, type_cb);
xml = mxmlLoadFd(/*top*/NULL, fd, type_cb, /*load_cbdata*/NULL, /*sax_cb*/NULL, /*sax_cbdata*/NULL);
close(fd);
@ -554,7 +546,7 @@ main(int argc, // I - Number of command-line args
}
// Write the file...
mxmlSaveFd(xml, fd, whitespace_cb);
mxmlSaveFd(xml, fd, whitespace_cb, /*save_cbdata*/NULL);
close(fd);
@ -566,21 +558,9 @@ main(int argc, // I - Number of command-line args
memset(event_counts, 0, sizeof(event_counts));
if (argv[1][0] == '<')
{
mxmlRelease(mxmlSAXLoadString(NULL, argv[1], type_cb, sax_cb, NULL));
}
else if ((fp = fopen(argv[1], "rb")) == NULL)
{
perror(argv[1]);
return (1);
}
mxmlRelease(mxmlLoadString(/*top*/NULL, argv[1], type_cb, /*load_cbdata*/NULL, sax_cb, /*sax_cbdata*/NULL));
else
{
// Read the file...
mxmlRelease(mxmlSAXLoadFile(NULL, fp, type_cb, sax_cb, NULL));
fclose(fp);
}
mxmlRelease(mxmlLoadFilename(/*top*/NULL, argv[1], type_cb, /*load_cbdata*/NULL, sax_cb, /*sax_cbdata*/NULL));
if (!strcmp(argv[1], "test.xml"))
{
@ -654,9 +634,9 @@ main(int argc, // I - Number of command-line args
//
bool // O - `true` to continue, `false` to stop
sax_cb(mxml_node_t *node, // I - Current node
mxml_sax_event_t event, // I - SAX event
void *data) // I - SAX user data
sax_cb(void *cbdata, // I - SAX callback data (not used)
mxml_node_t *node, // I - Current node
mxml_sax_event_t event) // I - SAX event
{
static const char * const events[] = // Events
{
@ -670,7 +650,7 @@ sax_cb(mxml_node_t *node, // I - Current node
};
(void)data;
(void)cbdata;
// This SAX callback just counts the different events.
if (!node)
@ -687,14 +667,20 @@ sax_cb(mxml_node_t *node, // I - Current node
//
mxml_type_t // O - Data type
type_cb(mxml_node_t *node) // I - Element node
type_cb(void *cbdata, // I - Callback data
mxml_node_t *node) // I - Element node
{
const char *type; // Type string
(void)cbdata;
// You can lookup attributes and/or use the element name, hierarchy, etc...
if ((type = mxmlElementGetAttr(node, "type")) == NULL)
type = node->value.element.name;
{
if ((type = mxmlGetElement(node)) == NULL)
type = "";
}
if (!strcmp(type, "integer"))
return (MXML_TYPE_INTEGER);
@ -713,8 +699,9 @@ type_cb(mxml_node_t *node) // I - Element node
//
const char * // O - Whitespace string or NULL
whitespace_cb(mxml_node_t *node, // I - Element node
int where) // I - Open or close tag?
whitespace_cb(void *cbdata, // I - Callback data
mxml_node_t *node, // I - Element node
mxml_ws_t where) // I - Open or close tag?
{
mxml_node_t *parent; // Parent node
int level; // Indentation level
@ -723,6 +710,8 @@ whitespace_cb(mxml_node_t *node, // I - Element node
// Tabs for indentation
(void)cbdata;
// We can conditionally break to a new line before or after any element.
// These are just common HTML elements...
if ((name = mxmlGetElement(node)) == NULL)
@ -756,7 +745,7 @@ whitespace_cb(mxml_node_t *node, // I - Element node
}
else if (where == MXML_WS_BEFORE_OPEN || ((!strcmp(name, "choice") || !strcmp(name, "option")) && where == MXML_WS_BEFORE_CLOSE))
{
for (level = -1, parent = node->parent; parent; level ++, parent = parent->parent);
for (level = -1, parent = mxmlGetParent(node); parent; level ++, parent = mxmlGetParent(parent));
if (level > 8)
level = 8;

Loading…
Cancel
Save