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)
- 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 the SAX callback to return a `bool` value to control processing
(Issue #51)
# Changes in Mini-XML 3.3.2

View File

@ -154,13 +154,13 @@ functions retrieve the value from a node:
mxml_node_t *node;
int intvalue = mxmlGetInteger(node);
long intvalue = mxmlGetInteger(node);
const char *opaquevalue = mxmlGetOpaque(node);
double realvalue = mxmlGetReal(node);
int whitespacevalue;
bool whitespacevalue;
const char *textvalue = mxmlGetText(node, &whitespacevalue);
.fi
.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
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
@ -1172,14 +1172,18 @@ mxmlSAXLoadString(mxml_node_t *top, const char *s,
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:
node, an event code, and a user data pointer you supply and returns `true` to
continue processing or `false` to stop:
```c
void
bool
sax_cb(mxml_node_t *node, mxml_sax_event_t event,
void *data)
{
... 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_COMMENT`: A comment was just read.
- `MXML_SAX_EVENT_DATA`: Data (
--------------------, integer, opaque, real, or text) was just read.
- `MXML_SAX_EVENT_DATA`: Data (integer, opaque, real, or text) 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_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:
```c
void
bool
sax_cb(mxml_node_t *node, mxml_sax_event_t event,
void *data)
{
if (event != MXML_SAX_ELEMENT_CLOSE)
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 ... >`:
```c
void
bool
sax_cb(mxml_node_t *node, mxml_sax_event_t event,
void *data)
{
@ -1256,6 +1261,8 @@ sax_cb(mxml_node_t *node, mxml_sax_event_t event,
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:
- 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`.
- Functions that returned `0` on success and `-1` on error now return `true` on
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
mxml \- Mini-XML API
.SH INCLUDE FILE
@ -157,13 +157,13 @@ functions retrieve the value from a node:
mxml_node_t *node;
int intvalue = mxmlGetInteger(node);
long intvalue = mxmlGetInteger(node);
const char *opaquevalue = mxmlGetOpaque(node);
double realvalue = mxmlGetReal(node);
int whitespacevalue;
bool whitespacevalue;
const char *textvalue = mxmlGetText(node, &whitespacevalue);
.fi
.PP
@ -1505,7 +1505,7 @@ typedef const char *(*)(mxml_node_t *, int) mxml_save_cb_t;
SAX callback function
.PP
.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
.SS mxml_sax_event_t
SAX event type.

Binary file not shown.

View File

@ -437,7 +437,7 @@ span.string {
<pre><code>gcc -o myprogram myprogram.c -lmxml
</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>
<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>
<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>
@ -1151,12 +1151,15 @@ mxmlSAXLoadString(mxml_node_t *top, <span class="reserved">const</span> <span cl
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:</p>
<pre><code class="language-c"><span class="reserved">void</span>
<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">bool</span>
sax_cb(mxml_node_t *node, mxml_sax_event_t event,
<span class="reserved">void</span> *data)
{
... <span class="reserved">do</span> something ...
<span class="comment">// Continue processing...</span>
<span class="reserved">return</span> (<span class="reserved">true</span>);
}
</code></pre>
<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><p><code>MXML_SAX_EVENT_COMMENT</code>: A comment was just read.</p>
</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><p><code>MXML_SAX_EVENT_DECLARATION</code>: A declaration was just read.</p>
</li>
@ -1177,16 +1180,18 @@ sax_cb(mxml_node_t *node, mxml_sax_event_t event,
</li>
</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">void</span>
<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)
{
<span class="reserved">if</span> (event != MXML_SAX_ELEMENT_CLOSE)
mxmlRetain(node);
<span class="reserved">return</span> (<span class="reserved">true</span>);
}
</code></pre>
<p>More typically the SAX callback will only retain a small portion of the document that is needed for post-processing. For example, the following SAX callback will retain the title and headings in an XHTML file. It also retains the (parent) elements like <code>&lt;html&gt;</code>, <code>&lt;head&gt;</code>, and <code>&lt;body&gt;</code>, and processing directives like <code>&lt;?xml ... ?&gt;</code> and declarations like <code>&lt;!DOCTYPE ... &gt;</code>:</p>
<pre><code class="language-c"><span class="reserved">void</span>
<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)
{
@ -1226,6 +1231,8 @@ sax_cb(mxml_node_t *node, mxml_sax_event_t event,
mxmlRetain(node);
}
}
<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>
@ -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>
<p>The following incompatible API changes were made in Mini-XML v4.0:</p>
<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><p>Node types are now named <code>MXML_TYPE_foo</code> instead of <code>MXML_foo</code>.</p>
</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>
<p class="description">SAX callback function</p>
<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>
<h3 class="typedef"><a id="mxml_sax_event_t">mxml_sax_event_t</a></h3>
<p class="description">SAX event type.</p>

View File

@ -1341,7 +1341,8 @@ mxml_load_data(
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))
node = NULL;
@ -1367,7 +1368,8 @@ mxml_load_data(
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))
node = NULL;
@ -1464,7 +1466,8 @@ mxml_load_data(
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))
node = NULL;
@ -1520,7 +1523,8 @@ mxml_load_data(
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))
node = NULL;
@ -1570,7 +1574,8 @@ mxml_load_data(
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))
node = NULL;
@ -1645,7 +1650,8 @@ mxml_load_data(
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))
node = NULL;
@ -1686,7 +1692,8 @@ mxml_load_data(
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))
{
@ -1737,7 +1744,10 @@ mxml_load_data(
}
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)
first = node;
@ -1757,7 +1767,8 @@ mxml_load_data(
}
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))
{

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);
// 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