mirror of
https://github.com/michaelrsweet/mxml.git
synced 2024-11-24 11:25:30 +00:00
Add mxmlLoadIO/mxmlSaveIO functions, merge everything under the new roof
(Issue #98)
This commit is contained in:
parent
e54574aca7
commit
4e92848ae2
@ -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)
|
||||
|
164
doc/body.md
164
doc/body.md
@ -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.
|
||||
|
276
doc/mxml.3
276
doc/mxml.3
@ -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
|
||||
|
BIN
doc/mxml.epub
BIN
doc/mxml.epub
Binary file not shown.
486
doc/mxml.html
486
doc/mxml.html
@ -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 "filename.xml" 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 "filename.xml" 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">"filename.xml"</span>, <span class="string">"r"</span>);
|
||||
tree = mxmlLoadFile(NULL, fp, MXML_OPAQUE_CALLBACK);
|
||||
tree = mxmlLoadFile(<span class="comment">/*top*/</span>NULL, fp, <span class="comment">/*load_cb*/</span>NULL, &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 "type" 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">"filename.xml"</span>, <span class="string">"r"</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"><?xml version=<span class="string">"1.0"</span> encoding=<span class="string">"utf-8"</span>?>
|
||||
<pre><code><?xml version="1.0" encoding="utf-8"?>
|
||||
<data>
|
||||
<node>
|
||||
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 "yyyy-mm-ddThh:mm:ssZ" (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 "yyyy-mm-ddThh:mm:ssZ" (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->unix = gmtime(&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><html></code>, <code><head></code>, and <code><body></code>, and processing directives like <code><?xml ... ?></code> and declarations like <code><!DOCTYPE ... ></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">"title"</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 ("&");
|
||||
|
||||
case '<' :
|
||||
return ("lt");
|
||||
return ("<");
|
||||
|
||||
case '>' :
|
||||
return ("gt");
|
||||
return (">");
|
||||
|
||||
case '\"' :
|
||||
return ("quot");
|
||||
return (""");
|
||||
|
||||
default :
|
||||
return (NULL);
|
||||
|
2532
mxml-file.c
2532
mxml-file.c
File diff suppressed because it is too large
Load Diff
34
mxml-get.c
34
mxml-get.c
@ -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
|
||||
|
84
mxml-set.c
84
mxml-set.c
@ -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);
|
||||
}
|
||||
|
||||
|
91
mxml.h
91
mxml.h
@ -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
|
||||
|
213
testmxml.c
213
testmxml.c
@ -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…
Reference in New Issue
Block a user