Add mxmlFindValue API (STR #110)

pull/193/head
Michael R Sweet 14 years ago
parent b9a4a5e22e
commit 159e54f5d2
  1. 4
      CHANGES
  2. 7
      README
  3. 13
      doc/basics.html
  4. 7
      doc/intro.man
  5. 23
      doc/reference.html
  6. 6
      doc/relnotes.html
  7. 82
      mxml-search.c
  8. 1
      mxml.h
  9. 21
      mxml.xml
  10. 13
      mxmldoc.c
  11. 54
      testmxml.c

@ -1,10 +1,12 @@
CHANGES - 2010-11-07 CHANGES - 2010-11-08
-------------------- --------------------
CHANGES IN Mini-XML 2.7 CHANGES IN Mini-XML 2.7
- Updated the source headers to reference the Mini-XML license and its - Updated the source headers to reference the Mini-XML license and its
exceptions to the LGPL2 (STR #108) 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 - Building a static version of the library did not work on Windows
(STR #112) (STR #112)
- The shared library did not include a destructor for the thread- - The shared library did not include a destructor for the thread-

@ -1,4 +1,4 @@
README - 2010-09-19 README - 2010-11-08
------------------- -------------------
@ -156,6 +156,11 @@ DOCUMENTATION
... do something ... ... 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()" 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 function to recursively free the memory that is used for a particular node
or the entire tree: or the entire tree:

@ -522,5 +522,18 @@ three constants:</p>
</ul> </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> </body>
</html> </html>

@ -141,6 +141,13 @@ You can also iterate with the same function:
} }
.fi .fi
.PP .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 Finally, once you are done with the XML data, use the
"mxmlDelete()" function to recursively free the memory that "mxmlDelete()" function to recursively free the memory that
is used for a particular node or the entire tree: is used for a particular node or the entire tree:

@ -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="#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="#mxmlEntityRemoveCallback" title="Remove a callback.">mxmlEntityRemoveCallback</a></li>
<li><a href="#mxmlFindElement" title="Find the named element.">mxmlFindElement</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="#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="#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> <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 MXML_DESCEND_FIRST for the initial search and MXML_NO_DESCEND to find
additional direct descendents of the node. The top node argument additional direct descendents of the node. The top node argument
constrains the search to a particular node's children.</p> 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> <h3 class="function"><a name="mxmlIndexDelete">mxmlIndexDelete</a></h3>
<p class="description">Delete an index.</p> <p class="description">Delete an index.</p>
<p class="code"> <p class="code">

@ -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 <li>Updated the source headers to reference the Mini-XML license and its
exceptions to the LGPL2 (STR #108)</li> 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- <li>The shared library did not include a destructor for the thread-
specific data key on UNIX-based operating systems (STR #103)</li> specific data key on UNIX-based operating systems (STR #103)</li>

@ -17,6 +17,7 @@
* Contents: * Contents:
* *
* mxmlFindElement() - Find the named element. * mxmlFindElement() - Find the named element.
* mxmlFindValue() - Find a value with the given path.
* mxmlWalkNext() - Walk to the next logical node in the tree. * mxmlWalkNext() - Walk to the next logical node in the tree.
* mxmlWalkPrev() - Walk to the previous 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. * 'mxmlWalkNext()' - Walk to the next logical node in the tree.
* *

@ -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, extern mxml_node_t *mxmlFindElement(mxml_node_t *node, mxml_node_t *top,
const char *name, const char *attr, const char *name, const char *attr,
const char *value, int descend); 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 void mxmlIndexDelete(mxml_index_t *ind);
extern mxml_node_t *mxmlIndexEnum(mxml_index_t *ind); extern mxml_node_t *mxmlIndexEnum(mxml_index_t *ind);
extern mxml_node_t *mxmlIndexFind(mxml_index_t *ind, extern mxml_node_t *mxmlIndexFind(mxml_index_t *ind,

@ -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> <description>Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST</description>
</argument> </argument>
</function> </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"> <function name="mxmlIndexDelete">
<description>Delete an index.</description> <description>Delete an index.</description>
<argument name="ind" direction="I"> <argument name="ind" direction="I">

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

@ -130,6 +130,8 @@ main(int argc, /* I - Number of command-line args */
MXML_REAL_CALLBACK); MXML_REAL_CALLBACK);
mxmlLoadString(tree, "<group>opaque opaque opaque</group>", mxmlLoadString(tree, "<group>opaque opaque opaque</group>",
MXML_OPAQUE_CALLBACK); MXML_OPAQUE_CALLBACK);
mxmlLoadString(tree, "<foo><bar><one><two>value<two>value2</two></two></one>"
"</bar></foo>", MXML_OPAQUE_CALLBACK);
node = tree->child; 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... * Test indices...
*/ */
@ -270,10 +318,10 @@ main(int argc, /* I - Number of command-line args */
return (1); return (1);
} }
if (ind->num_nodes != 5) if (ind->num_nodes != 10)
{ {
fprintf(stderr, "ERROR: Index of all nodes contains %d " 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); mxmlIndexDelete(ind);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -378,7 +426,7 @@ main(int argc, /* I - Number of command-line args */
* Check the mxmlDelete() works properly... * Check the mxmlDelete() works properly...
*/ */
for (i = 0; i < 8; i ++) for (i = 0; i < 9; i ++)
{ {
if (tree->child) if (tree->child)
mxmlDelete(tree->child); mxmlDelete(tree->child);

Loading…
Cancel
Save