SAX callback now returns a boolean (Issue #51)

This commit is contained in:
Michael R Sweet 2024-03-04 07:37:33 -05:00
parent 5c66db0383
commit 3df751f37b
No known key found for this signature in database
GPG Key ID: BE67C75EC81F3244
8 changed files with 62 additions and 32 deletions

View File

@ -5,6 +5,8 @@
`MXML_TYPE_DIRECTIVE` node types (Issue #250) `MXML_TYPE_DIRECTIVE` node types (Issue #250)
- Renamed `mxml_type_t` enumerations to `MXML_TYPE_xxx` (Issue #251) - Renamed `mxml_type_t` enumerations to `MXML_TYPE_xxx` (Issue #251)
- Updated APIs to use bool type instead of an int representing a boolean value. - Updated APIs to use bool type instead of an int representing a boolean value.
- Updated the SAX callback to return a `bool` value to control processing
(Issue #51)
# Changes in Mini-XML 3.3.2 # Changes in Mini-XML 3.3.2

View File

@ -154,13 +154,13 @@ functions retrieve the value from a node:
mxml_node_t *node; mxml_node_t *node;
int intvalue = mxmlGetInteger(node); long intvalue = mxmlGetInteger(node);
const char *opaquevalue = mxmlGetOpaque(node); const char *opaquevalue = mxmlGetOpaque(node);
double realvalue = mxmlGetReal(node); double realvalue = mxmlGetReal(node);
int whitespacevalue; bool whitespacevalue;
const char *textvalue = mxmlGetText(node, &whitespacevalue); const char *textvalue = mxmlGetText(node, &whitespacevalue);
.fi .fi
.PP .PP

View File

@ -88,7 +88,7 @@ The Mini-XML library is included with your program using the `-lmxml` option:
If you have the `pkg-config` software installed, you can use it to determine the If you have the `pkg-config` software installed, you can use it to determine the
proper compiler and linker options for your installation: proper compiler and linker options for your installation:
gcc `pkg-config --cflags mxml` -o myprogram myprogram.c `pkg-config --libs mxml` gcc `pkg-config --cflags mxml4` -o myprogram myprogram.c `pkg-config --libs mxml4`
Loading an XML File Loading an XML File
@ -1172,14 +1172,18 @@ mxmlSAXLoadString(mxml_node_t *top, const char *s,
Each function works like the corresponding `mxmlLoad` function but uses a 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 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: node, an event code, and a user data pointer you supply and returns `true` to
continue processing or `false` to stop:
```c ```c
void bool
sax_cb(mxml_node_t *node, mxml_sax_event_t event, sax_cb(mxml_node_t *node, mxml_sax_event_t event,
void *data) void *data)
{ {
... do something ... ... do something ...
// Continue processing...
return (true);
} }
``` ```
@ -1187,8 +1191,7 @@ The event will be one of the following:
- `MXML_SAX_EVENT_CDATA`: CDATA was just read. - `MXML_SAX_EVENT_CDATA`: CDATA was just read.
- `MXML_SAX_EVENT_COMMENT`: A comment was just read. - `MXML_SAX_EVENT_COMMENT`: A comment was just read.
- `MXML_SAX_EVENT_DATA`: Data ( - `MXML_SAX_EVENT_DATA`: Data (integer, opaque, real, or text) was just read.
--------------------, integer, opaque, real, or text) was just read.
- `MXML_SAX_EVENT_DECLARATION`: A declaration was just read. - `MXML_SAX_EVENT_DECLARATION`: A declaration was just read.
- `MXML_SAX_EVENT_DIRECTIVE`: A processing directive/instruction was just read. - `MXML_SAX_EVENT_DIRECTIVE`: A processing directive/instruction was just read.
- `MXML_SAX_EVENT_ELEMENT_CLOSE` - A close element was just read \(`</element>`) - `MXML_SAX_EVENT_ELEMENT_CLOSE` - A close element was just read \(`</element>`)
@ -1200,12 +1203,14 @@ using the `mxmlRetain` function. For example, the following SAX callback will
retain all nodes, effectively simulating a normal in-memory load: retain all nodes, effectively simulating a normal in-memory load:
```c ```c
void bool
sax_cb(mxml_node_t *node, mxml_sax_event_t event, sax_cb(mxml_node_t *node, mxml_sax_event_t event,
void *data) void *data)
{ {
if (event != MXML_SAX_ELEMENT_CLOSE) if (event != MXML_SAX_ELEMENT_CLOSE)
mxmlRetain(node); mxmlRetain(node);
return (true);
} }
``` ```
@ -1216,7 +1221,7 @@ will retain the title and headings in an XHTML file. It also retains the
directives like `<?xml ... ?>` and declarations like `<!DOCTYPE ... >`: directives like `<?xml ... ?>` and declarations like `<!DOCTYPE ... >`:
```c ```c
void bool
sax_cb(mxml_node_t *node, mxml_sax_event_t event, sax_cb(mxml_node_t *node, mxml_sax_event_t event,
void *data) void *data)
{ {
@ -1256,6 +1261,8 @@ sax_cb(mxml_node_t *node, mxml_sax_event_t event,
mxmlRetain(node); mxmlRetain(node);
} }
} }
return (true);
} }
``` ```
@ -1320,7 +1327,8 @@ Migrating from Mini-XML v3.x
The following incompatible API changes were made in Mini-XML v4.0: The following incompatible API changes were made in Mini-XML v4.0:
- SAX events are not named `MXML_SAX_EVENT_foo` instead of `MXML_SAX_foo`. - SAX events are now named `MXML_SAX_EVENT_foo` instead of `MXML_SAX_foo`.
- SAX callbacks now return a boolean value.
- Node types are now named `MXML_TYPE_foo` instead of `MXML_foo`. - 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 - Functions that returned `0` on success and `-1` on error now return `true` on
success and `false` on error. success and `false` on error.

View File

@ -1,4 +1,4 @@
.TH mxml 3 "Mini-XML API" "2024-03-02" "Mini-XML API" .TH mxml 3 "Mini-XML API" "2024-03-04" "Mini-XML API"
.SH NAME .SH NAME
mxml \- Mini-XML API mxml \- Mini-XML API
.SH INCLUDE FILE .SH INCLUDE FILE
@ -157,13 +157,13 @@ functions retrieve the value from a node:
mxml_node_t *node; mxml_node_t *node;
int intvalue = mxmlGetInteger(node); long intvalue = mxmlGetInteger(node);
const char *opaquevalue = mxmlGetOpaque(node); const char *opaquevalue = mxmlGetOpaque(node);
double realvalue = mxmlGetReal(node); double realvalue = mxmlGetReal(node);
int whitespacevalue; bool whitespacevalue;
const char *textvalue = mxmlGetText(node, &whitespacevalue); const char *textvalue = mxmlGetText(node, &whitespacevalue);
.fi .fi
.PP .PP
@ -1505,7 +1505,7 @@ typedef const char *(*)(mxml_node_t *, int) mxml_save_cb_t;
SAX callback function SAX callback function
.PP .PP
.nf .nf
typedef void(*)(mxml_node_t *, mxml_sax_event_t, void *) mxml_sax_cb_t; typedef bool(*)(mxml_node_t *, mxml_sax_event_t, void *) mxml_sax_cb_t;
.fi .fi
.SS mxml_sax_event_t .SS mxml_sax_event_t
SAX event type. SAX event type.

Binary file not shown.

View File

@ -437,7 +437,7 @@ span.string {
<pre><code>gcc -o myprogram myprogram.c -lmxml <pre><code>gcc -o myprogram myprogram.c -lmxml
</code></pre> </code></pre>
<p>If you have the <code>pkg-config</code> software installed, you can use it to determine the proper compiler and linker options for your installation:</p> <p>If you have the <code>pkg-config</code> software installed, you can use it to determine the proper compiler and linker options for your installation:</p>
<pre><code>gcc `pkg-config --cflags mxml` -o myprogram myprogram.c `pkg-config --libs mxml` <pre><code>gcc `pkg-config --cflags mxml4` -o myprogram myprogram.c `pkg-config --libs mxml4`
</code></pre> </code></pre>
<h3 class="title" id="loading-an-xml-file">Loading an XML File</h3> <h3 class="title" id="loading-an-xml-file">Loading an XML File</h3>
<p>You load an XML file using the <code>mxmlLoadFile</code> function:</p> <p>You load an XML file using the <code>mxmlLoadFile</code> function:</p>
@ -1151,12 +1151,15 @@ mxmlSAXLoadString(mxml_node_t *top, <span class="reserved">const</span> <span cl
mxml_type_t (*cb)(mxml_node_t *), mxml_type_t (*cb)(mxml_node_t *),
mxml_sax_cb_t sax, <span class="reserved">void</span> *sax_data); mxml_sax_cb_t sax, <span class="reserved">void</span> *sax_data);
</code></pre> </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:</p> <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>
<pre><code class="language-c"><span class="reserved">void</span> <pre><code class="language-c"><span class="reserved">bool</span>
sax_cb(mxml_node_t *node, mxml_sax_event_t event, sax_cb(mxml_node_t *node, mxml_sax_event_t event,
<span class="reserved">void</span> *data) <span class="reserved">void</span> *data)
{ {
... <span class="reserved">do</span> something ... ... <span class="reserved">do</span> something ...
<span class="comment">// Continue processing...</span>
<span class="reserved">return</span> (<span class="reserved">true</span>);
} }
</code></pre> </code></pre>
<p>The event will be one of the following:</p> <p>The event will be one of the following:</p>
@ -1165,7 +1168,7 @@ sax_cb(mxml_node_t *node, mxml_sax_event_t event,
</li> </li>
<li><p><code>MXML_SAX_EVENT_COMMENT</code>: A comment was just read.</p> <li><p><code>MXML_SAX_EVENT_COMMENT</code>: A comment was just read.</p>
</li> </li>
<li><p><code>MXML_SAX_EVENT_DATA</code>: Data ( --------------------, integer, opaque, real, or text) was just read.</p> <li><p><code>MXML_SAX_EVENT_DATA</code>: Data (integer, opaque, real, or text) was just read.</p>
</li> </li>
<li><p><code>MXML_SAX_EVENT_DECLARATION</code>: A declaration was just read.</p> <li><p><code>MXML_SAX_EVENT_DECLARATION</code>: A declaration was just read.</p>
</li> </li>
@ -1177,16 +1180,18 @@ sax_cb(mxml_node_t *node, mxml_sax_event_t event,
</li> </li>
</ul> </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> <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">void</span> <pre><code class="language-c"><span class="reserved">bool</span>
sax_cb(mxml_node_t *node, mxml_sax_event_t event, sax_cb(mxml_node_t *node, mxml_sax_event_t event,
<span class="reserved">void</span> *data) <span class="reserved">void</span> *data)
{ {
<span class="reserved">if</span> (event != MXML_SAX_ELEMENT_CLOSE) <span class="reserved">if</span> (event != MXML_SAX_ELEMENT_CLOSE)
mxmlRetain(node); mxmlRetain(node);
<span class="reserved">return</span> (<span class="reserved">true</span>);
} }
</code></pre> </code></pre>
<p>More typically the SAX callback will only retain a small portion of the document that is needed for post-processing. For example, the following SAX callback will retain the title and headings in an XHTML file. It also retains the (parent) elements like <code>&lt;html&gt;</code>, <code>&lt;head&gt;</code>, and <code>&lt;body&gt;</code>, and processing directives like <code>&lt;?xml ... ?&gt;</code> and declarations like <code>&lt;!DOCTYPE ... &gt;</code>:</p> <p>More typically the SAX callback will only retain a small portion of the document that is needed for post-processing. For example, the following SAX callback will retain the title and headings in an XHTML file. It also retains the (parent) elements like <code>&lt;html&gt;</code>, <code>&lt;head&gt;</code>, and <code>&lt;body&gt;</code>, and processing directives like <code>&lt;?xml ... ?&gt;</code> and declarations like <code>&lt;!DOCTYPE ... &gt;</code>:</p>
<pre><code class="language-c"><span class="reserved">void</span> <pre><code class="language-c"><span class="reserved">bool</span>
sax_cb(mxml_node_t *node, mxml_sax_event_t event, sax_cb(mxml_node_t *node, mxml_sax_event_t event,
<span class="reserved">void</span> *data) <span class="reserved">void</span> *data)
{ {
@ -1226,6 +1231,8 @@ sax_cb(mxml_node_t *node, mxml_sax_event_t event,
mxmlRetain(node); mxmlRetain(node);
} }
} }
<span class="reserved">return</span> (<span class="reserved">true</span>);
} }
</code></pre> </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 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>
@ -1277,7 +1284,9 @@ print_children(mxml_node_t *parent)
<h2 class="title" id="migrating-from-mini-xml-v3.x">Migrating from Mini-XML v3.x</h2> <h2 class="title" id="migrating-from-mini-xml-v3.x">Migrating from Mini-XML v3.x</h2>
<p>The following incompatible API changes were made in Mini-XML v4.0:</p> <p>The following incompatible API changes were made in Mini-XML v4.0:</p>
<ul> <ul>
<li><p>SAX events are not named <code>MXML_SAX_EVENT_foo</code> instead of <code>MXML_SAX_foo</code>.</p> <li><p>SAX events are now named <code>MXML_SAX_EVENT_foo</code> instead of <code>MXML_SAX_foo</code>.</p>
</li>
<li><p>SAX callbacks now return a boolean value.</p>
</li> </li>
<li><p>Node types are now named <code>MXML_TYPE_foo</code> instead of <code>MXML_foo</code>.</p> <li><p>Node types are now named <code>MXML_TYPE_foo</code> instead of <code>MXML_foo</code>.</p>
</li> </li>
@ -2874,7 +2883,7 @@ typedef const char *(*mxml_save_cb_t)(<a href="#mxml_node_t">mxml_node_t</a> *,
<h3 class="typedef"><a id="mxml_sax_cb_t">mxml_sax_cb_t</a></h3> <h3 class="typedef"><a id="mxml_sax_cb_t">mxml_sax_cb_t</a></h3>
<p class="description">SAX callback function</p> <p class="description">SAX callback function</p>
<p class="code"> <p class="code">
typedef void (*mxml_sax_cb_t)(<a href="#mxml_node_t">mxml_node_t</a> *, mxml_sax_event_t, void *); typedef bool (*mxml_sax_cb_t)(<a href="#mxml_node_t">mxml_node_t</a> *, mxml_sax_event_t, void *);
</p> </p>
<h3 class="typedef"><a id="mxml_sax_event_t">mxml_sax_event_t</a></h3> <h3 class="typedef"><a id="mxml_sax_event_t">mxml_sax_event_t</a></h3>
<p class="description">SAX event type.</p> <p class="description">SAX event type.</p>

View File

@ -1341,7 +1341,8 @@ mxml_load_data(
if (sax_cb) if (sax_cb)
{ {
(*sax_cb)(node, MXML_SAX_EVENT_DATA, sax_data); if (!(*sax_cb)(node, MXML_SAX_EVENT_DATA, sax_data))
goto error;
if (!mxmlRelease(node)) if (!mxmlRelease(node))
node = NULL; node = NULL;
@ -1367,7 +1368,8 @@ mxml_load_data(
if (sax_cb) if (sax_cb)
{ {
(*sax_cb)(node, MXML_SAX_EVENT_DATA, sax_data); if (!(*sax_cb)(node, MXML_SAX_EVENT_DATA, sax_data))
goto error;
if (!mxmlRelease(node)) if (!mxmlRelease(node))
node = NULL; node = NULL;
@ -1464,7 +1466,8 @@ mxml_load_data(
if (sax_cb) if (sax_cb)
{ {
(*sax_cb)(node, MXML_SAX_EVENT_COMMENT, sax_data); if (!(*sax_cb)(node, MXML_SAX_EVENT_COMMENT, sax_data))
goto error;
if (!mxmlRelease(node)) if (!mxmlRelease(node))
node = NULL; node = NULL;
@ -1520,7 +1523,8 @@ mxml_load_data(
if (sax_cb) if (sax_cb)
{ {
(*sax_cb)(node, MXML_SAX_EVENT_CDATA, sax_data); if (!(*sax_cb)(node, MXML_SAX_EVENT_CDATA, sax_data))
goto error;
if (!mxmlRelease(node)) if (!mxmlRelease(node))
node = NULL; node = NULL;
@ -1570,7 +1574,8 @@ mxml_load_data(
if (sax_cb) if (sax_cb)
{ {
(*sax_cb)(node, MXML_SAX_EVENT_DIRECTIVE, sax_data); if (!(*sax_cb)(node, MXML_SAX_EVENT_DIRECTIVE, sax_data))
goto error;
if (strncmp(node->value.directive, "xml ", 4) && !mxmlRelease(node)) if (strncmp(node->value.directive, "xml ", 4) && !mxmlRelease(node))
node = NULL; node = NULL;
@ -1645,7 +1650,8 @@ mxml_load_data(
if (sax_cb) if (sax_cb)
{ {
(*sax_cb)(node, MXML_SAX_EVENT_DECLARATION, sax_data); if (!(*sax_cb)(node, MXML_SAX_EVENT_DECLARATION, sax_data))
goto error;
if (!mxmlRelease(node)) if (!mxmlRelease(node))
node = NULL; node = NULL;
@ -1686,7 +1692,8 @@ mxml_load_data(
if (sax_cb) if (sax_cb)
{ {
(*sax_cb)(node, MXML_SAX_EVENT_ELEMENT_CLOSE, sax_data); if (!(*sax_cb)(node, MXML_SAX_EVENT_ELEMENT_CLOSE, sax_data))
goto error;
if (!mxmlRelease(node)) if (!mxmlRelease(node))
{ {
@ -1737,7 +1744,10 @@ mxml_load_data(
} }
if (sax_cb) if (sax_cb)
(*sax_cb)(node, MXML_SAX_EVENT_ELEMENT_OPEN, sax_data); {
if (!(*sax_cb)(node, MXML_SAX_EVENT_ELEMENT_OPEN, sax_data))
goto error;
}
if (!first) if (!first)
first = node; first = node;
@ -1757,7 +1767,8 @@ mxml_load_data(
} }
else if (sax_cb) else if (sax_cb)
{ {
(*sax_cb)(node, MXML_SAX_EVENT_ELEMENT_CLOSE, sax_data); if (!(*sax_cb)(node, MXML_SAX_EVENT_ELEMENT_CLOSE, sax_data))
goto error;
if (!mxmlRelease(node)) if (!mxmlRelease(node))
{ {

2
mxml.h
View File

@ -120,7 +120,7 @@ typedef mxml_type_t (*mxml_load_cb_t)(mxml_node_t *);
typedef const char *(*mxml_save_cb_t)(mxml_node_t *, int); typedef const char *(*mxml_save_cb_t)(mxml_node_t *, int);
// Save callback function // Save callback function
typedef void (*mxml_sax_cb_t)(mxml_node_t *, mxml_sax_event_t, void *); typedef bool (*mxml_sax_cb_t)(mxml_node_t *, mxml_sax_event_t, void *);
// SAX callback function // SAX callback function