mirror of
https://github.com/michaelrsweet/mxml.git
synced 2024-11-13 07:15:30 +00:00
Add mxmlFindValue API (STR #110)
This commit is contained in:
parent
b9a4a5e22e
commit
159e54f5d2
4
CHANGES
4
CHANGES
@ -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
7
README
@ -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:
|
||||
|
@ -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>
|
||||
|
@ -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:
|
||||
|
@ -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"> Mini-XML 2.7 </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>
|
||||
<a href="#mxml_node_t">mxml_node_t</a> *top,<br>
|
||||
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 "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.
|
||||
|
||||
</p>
|
||||
<h3 class="function"><a name="mxmlIndexDelete">mxmlIndexDelete</a></h3>
|
||||
<p class="description">Delete an index.</p>
|
||||
<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
|
||||
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>
|
||||
|
||||
|
@ -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
1
mxml.h
@ -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,
|
||||
|
21
mxml.xml
21
mxml.xml
@ -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 "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@</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">
|
||||
|
13
mxmldoc.c
13
mxmldoc.c
@ -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, ' ');
|
||||
|
54
testmxml.c
54
testmxml.c
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user