Add mxmlFindValue API (STR #110)

This commit is contained in:
Michael R Sweet 2010-11-08 16:07:05 +00:00
parent b9a4a5e22e
commit 159e54f5d2
11 changed files with 224 additions and 7 deletions

View File

@ -1,10 +1,12 @@
CHANGES - 2010-11-07
CHANGES - 2010-11-08
--------------------
CHANGES IN Mini-XML 2.7
- Updated the source headers to reference the Mini-XML license and its
exceptions to the LGPL2 (STR #108)
- Added a new mxmlFindValue() function to find the value node of a
named element (STR #110)
- Building a static version of the library did not work on Windows
(STR #112)
- The shared library did not include a destructor for the thread-

7
README
View File

@ -1,4 +1,4 @@
README - 2010-09-19
README - 2010-11-08
-------------------
@ -156,6 +156,11 @@ DOCUMENTATION
... do something ...
}
The "mxmlFindValue()" function finds the (first) value node under a specific
element using a "path":
mxml_node_t *value = mxmlFindValue(tree, "path/to/*/foo/bar");
Finally, once you are done with the XML data, use the "mxmlDelete()"
function to recursively free the memory that is used for a particular node
or the entire tree:

View File

@ -522,5 +522,18 @@ three constants:</p>
</ul>
<h2>Finding Value Nodes</h2>
<p>You can find the value of a specific node in the tree using the <a
href='#mxmlFindValue'><tt>mxmlFindValue</tt></a>, for example:
<pre>
mxml_node_t *value = mxmlFindValue(tree, "path/to/*/foo/bar");
</pre>
<p>The second argument is a "path" to the parent node. Each component of the
path is separated by a slash (/) and represents a named element in the document
tree or a wildcard (*) path representing 0 or more intervening nodes.</p>
</body>
</html>

View File

@ -141,6 +141,13 @@ You can also iterate with the same function:
}
.fi
.PP
To find the value of a specific node in the tree, use the "mxmlFindValue()"
function:
.nf
mxml_node_t *value = mxmlFindValue(tree, "path/to/*/foo/bar");
.fi
.PP
Finally, once you are done with the XML data, use the
"mxmlDelete()" function to recursively free the memory that
is used for a particular node or the entire tree:

View File

@ -155,6 +155,7 @@ Reference</h1>
<li><a href="#mxmlEntityGetValue" title="Get the character corresponding to a named entity.">mxmlEntityGetValue</a></li>
<li><a href="#mxmlEntityRemoveCallback" title="Remove a callback.">mxmlEntityRemoveCallback</a></li>
<li><a href="#mxmlFindElement" title="Find the named element.">mxmlFindElement</a></li>
<li><a href="#mxmlFindValue" title="Find a value with the given path.">mxmlFindValue</a></li>
<li><a href="#mxmlIndexDelete" title="Delete an index.">mxmlIndexDelete</a></li>
<li><a href="#mxmlIndexEnum" title="Return the next node in the index.">mxmlIndexEnum</a></li>
<li><a href="#mxmlIndexFind" title="Find the next matching node.">mxmlIndexFind</a></li>
@ -450,6 +451,28 @@ whether the search descends into child nodes; normally you will use
MXML_DESCEND_FIRST for the initial search and MXML_NO_DESCEND to find
additional direct descendents of the node. The top node argument
constrains the search to a particular node's children.</p>
<h3 class="function"><span class="info">&nbsp;Mini-XML 2.7&nbsp;</span><a name="mxmlFindValue">mxmlFindValue</a></h3>
<p class="description">Find a value with the given path.</p>
<p class="code">
<a href="#mxml_node_t">mxml_node_t</a> *mxmlFindValue (<br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mxml_node_t">mxml_node_t</a> *top,<br>
&nbsp;&nbsp;&nbsp;&nbsp;const char *path<br>
);</p>
<h4 class="parameters">Parameters</h4>
<dl>
<dt>top</dt>
<dd class="description">Top node</dd>
<dt>path</dt>
<dd class="description">Path to element</dd>
</dl>
<h4 class="returnvalue">Return Value</h4>
<p class="description">First value node or NULL</p>
<h4 class="discussion">Discussion</h4>
<p class="discussion">The &quot;path&quot; is a slash-separated list of element names. The name &quot;*&quot; is
considered a wildcard for one or more levels of elements. For example,
&quot;foo/one/two&quot;, &quot;bar/two/one&quot;, &quot;*/one&quot;, and so forth.
</p>
<h3 class="function"><a name="mxmlIndexDelete">mxmlIndexDelete</a></h3>
<p class="description">Delete an index.</p>
<p class="code">

View File

@ -12,6 +12,12 @@ hspace="10" width="100" height="100" alt="B"></a>Release Notes</h1>
<li>Updated the source headers to reference the Mini-XML license and its
exceptions to the LGPL2 (STR #108)</li>
<li>Added a new mxmlFindValue() function to find the value node of a
named element (STR #110)</li>
<li>Building a static version of the library did not work on Windows
(STR #112)</li>
<li>The shared library did not include a destructor for the thread-
specific data key on UNIX-based operating systems (STR #103)</li>

View File

@ -17,6 +17,7 @@
* Contents:
*
* mxmlFindElement() - Find the named element.
* mxmlFindValue() - Find a value with the given path.
* mxmlWalkNext() - Walk to the next logical node in the tree.
* mxmlWalkPrev() - Walk to the previous logical node in the tree.
*/
@ -116,6 +117,87 @@ mxmlFindElement(mxml_node_t *node, /* I - Current node */
}
/*
* 'mxmlFindValue()' - Find a value with the given path.
*
* The "path" is a slash-separated list of element names. The name "*" is
* considered a wildcard for one or more levels of elements. For example,
* "foo/one/two", "bar/two/one", "*\/one", and so forth.
*
* @since Mini-XML 2.7@
*/
mxml_node_t * /* O - First value node or NULL */
mxmlFindValue(mxml_node_t *top, /* I - Top node */
const char *path) /* I - Path to element */
{
mxml_node_t *node; /* Current node */
char element[256], /* Current element name */
*pathsep; /* Separator in path */
int descend; /* mxmlFindElement option */
/*
* Range check input...
*/
if (!top || !path || !*path)
return (NULL);
/*
* Search each element in the path...
*/
node = top;
while (*path)
{
/*
* Handle wildcards...
*/
if (!strncmp(path, "*/", 2))
{
path += 2;
descend = MXML_DESCEND;
}
else
descend = MXML_DESCEND_FIRST;
/*
* Get the next element in the path...
*/
if ((pathsep = strchr(path, '/')) == NULL)
pathsep = path + strlen(path);
if (pathsep == path || (pathsep - path) >= sizeof(element))
return (NULL);
memcpy(element, path, pathsep - path);
element[pathsep - path] = '\0';
if (*pathsep)
path = pathsep + 1;
else
path = pathsep;
/*
* Search for the element...
*/
if ((node = mxmlFindElement(node, node, element, NULL, NULL,
descend)) == NULL)
return (NULL);
}
/*
* If we get this far, return the first child of the current node...
*/
return (node->child);
}
/*
* 'mxmlWalkNext()' - Walk to the next logical node in the tree.
*

1
mxml.h
View File

@ -205,6 +205,7 @@ extern void mxmlEntityRemoveCallback(mxml_entity_cb_t cb);
extern mxml_node_t *mxmlFindElement(mxml_node_t *node, mxml_node_t *top,
const char *name, const char *attr,
const char *value, int descend);
extern mxml_node_t *mxmlFindValue(mxml_node_t *node, const char *path);
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,

View File

@ -197,6 +197,27 @@ constrains the search to a particular node's children.</description>
<description>Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST</description>
</argument>
</function>
<function name="mxmlFindValue">
<returnvalue>
<type>mxml_node_t *</type>
<description>First value node or NULL</description>
</returnvalue>
<description>Find a value with the given path.
The &quot;path&quot; is a slash-separated list of element names. The name &quot;*&quot; is
considered a wildcard for one or more levels of elements. For example,
&quot;foo/one/two&quot;, &quot;bar/two/one&quot;, &quot;*/one&quot;, and so forth.
@since Mini-XML 2.7@</description>
<argument name="top" direction="I">
<type>mxml_node_t *</type>
<description>Top node</description>
</argument>
<argument name="path" direction="I">
<type>const char *</type>
<description>Path to element</description>
</argument>
</function>
<function name="mxmlIndexDelete">
<description>Delete an index.</description>
<argument name="ind" direction="I">

View File

@ -2627,7 +2627,16 @@ update_comment(mxml_node_t *parent, /* I - Parent node */
if (!parent || !comment)
return;
/*
* Convert "\/" to "/"...
*/
for (ptr = strstr(comment->value.text.string, "\\/");
ptr;
ptr = strstr(ptr, "\\/"))
safe_strcpy(ptr, ptr + 1);
/*
* Update the comment...
*/
@ -2662,7 +2671,7 @@ update_comment(mxml_node_t *parent, /* I - Parent node */
{
/*
* 'Convert "I - description", "IO - description", or "O - description"
* to description + directory attribute.
* to description + direction attribute.
*/
ptr = strchr(ptr, ' ');

View File

@ -130,6 +130,8 @@ main(int argc, /* I - Number of command-line args */
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);
node = tree->child;
@ -258,6 +260,52 @@ main(int argc, /* I - Number of command-line args */
}
}
/*
* Test mxmlFindValue...
*/
node = mxmlFindValue(tree, "*/two");
if (!node)
{
fputs("ERROR: Unable to find value for \"*/two\".\n", stderr);
mxmlDelete(tree);
return (1);
}
else if (node->type != MXML_OPAQUE || strcmp(node->value.opaque, "value"))
{
fputs("ERROR: Bad value for \"*/two\".\n", stderr);
mxmlDelete(tree);
return (1);
}
node = mxmlFindValue(tree, "foo/*/two");
if (!node)
{
fputs("ERROR: Unable to find value for \"foo/*/two\".\n", stderr);
mxmlDelete(tree);
return (1);
}
else if (node->type != MXML_OPAQUE || strcmp(node->value.opaque, "value"))
{
fputs("ERROR: Bad value for \"foo/*/two\".\n", stderr);
mxmlDelete(tree);
return (1);
}
node = mxmlFindValue(tree, "foo/bar/one/two");
if (!node)
{
fputs("ERROR: Unable to find value for \"foo/bar/one/two\".\n", stderr);
mxmlDelete(tree);
return (1);
}
else if (node->type != MXML_OPAQUE || strcmp(node->value.opaque, "value"))
{
fputs("ERROR: Bad value for \"foo/bar/one/two\".\n", stderr);
mxmlDelete(tree);
return (1);
}
/*
* Test indices...
*/
@ -270,10 +318,10 @@ main(int argc, /* I - Number of command-line args */
return (1);
}
if (ind->num_nodes != 5)
if (ind->num_nodes != 10)
{
fprintf(stderr, "ERROR: Index of all nodes contains %d "
"nodes; expected 5!\n", ind->num_nodes);
"nodes; expected 10!\n", ind->num_nodes);
mxmlIndexDelete(ind);
mxmlDelete(tree);
return (1);
@ -378,7 +426,7 @@ main(int argc, /* I - Number of command-line args */
* Check the mxmlDelete() works properly...
*/
for (i = 0; i < 8; i ++)
for (i = 0; i < 9; i ++)
{
if (tree->child)
mxmlDelete(tree->child);