2 * "$Id: mxml-search.c 451 2014-01-04 21:50:06Z msweet $"
4 * Search/navigation functions for Mini-XML, a small XML-like file
7 * Copyright 2003-2014 by Michael R Sweet.
9 * These coded instructions, statements, and computer programs are the
10 * property of Michael R Sweet and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "COPYING"
12 * which should have been included with this file. If this file is
13 * missing or damaged, see the license at:
15 * http://www.msweet.org/projects.php/Mini-XML
19 * Include necessary headers...
27 * 'mxmlFindElement()' - Find the named element.
29 * The search is constrained by the name, attribute name, and value; any
30 * NULL names or values are treated as wildcards, so different kinds of
31 * searches can be implemented by looking for all elements of a given name
32 * or all elements with a specific attribute. The descend argument determines
33 * whether the search descends into child nodes; normally you will use
34 * MXML_DESCEND_FIRST for the initial search and MXML_NO_DESCEND to find
35 * additional direct descendents of the node. The top node argument
36 * constrains the search to a particular node's children.
39 mxml_node_t * /* O - Element node or NULL */
40 mxmlFindElement(mxml_node_t *node, /* I - Current node */
41 mxml_node_t *top, /* I - Top node */
42 const char *name, /* I - Element name or NULL for any */
43 const char *attr, /* I - Attribute name, or NULL for none */
44 const char *value, /* I - Attribute value, or NULL for any */
45 int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */
47 const char *temp; /* Current attribute value */
51 * Range check input...
54 if (!node || !top || (!attr && value))
58 * Start with the next node...
61 node = mxmlWalkNext(node, top, descend);
64 * Loop until we find a matching element...
70 * See if this node matches...
73 if (node->type == MXML_ELEMENT &&
74 node->value.element.name &&
75 (!name || !strcmp(node->value.element.name, name)))
78 * See if we need to check for an attribute...
82 return (node); /* No attribute search, return it... */
85 * Check for the attribute...
88 if ((temp = mxmlElementGetAttr(node, attr)) != NULL)
91 * OK, we have the attribute, does it match?
94 if (!value || !strcmp(value, temp))
95 return (node); /* Yes, return it... */
100 * No match, move on to the next node...
103 if (descend == MXML_DESCEND)
104 node = mxmlWalkNext(node, top, MXML_DESCEND);
114 * 'mxmlFindPath()' - Find a node with the given path.
116 * The "path" is a slash-separated list of element names. The name "*" is
117 * considered a wildcard for one or more levels of elements. For example,
118 * "foo/one/two", "bar/two/one", "*\/one", and so forth.
120 * The first child node of the found node is returned if the given node has
121 * children and the first child is a value node.
123 * @since Mini-XML 2.7@
126 mxml_node_t * /* O - Found node or NULL */
127 mxmlFindPath(mxml_node_t *top, /* I - Top node */
128 const char *path) /* I - Path to element */
130 mxml_node_t *node; /* Current node */
131 char element[256]; /* Current element name */
132 const char *pathsep; /* Separator in path */
133 int descend; /* mxmlFindElement option */
137 * Range check input...
140 if (!top || !path || !*path)
144 * Search each element in the path...
151 * Handle wildcards...
154 if (!strncmp(path, "*/", 2))
157 descend = MXML_DESCEND;
160 descend = MXML_DESCEND_FIRST;
163 * Get the next element in the path...
166 if ((pathsep = strchr(path, '/')) == NULL)
167 pathsep = path + strlen(path);
169 if (pathsep == path || (pathsep - path) >= sizeof(element))
172 memcpy(element, path, pathsep - path);
173 element[pathsep - path] = '\0';
181 * Search for the element...
184 if ((node = mxmlFindElement(node, node, element, NULL, NULL,
190 * If we get this far, return the node or its first child...
193 if (node->child && node->child->type != MXML_ELEMENT)
194 return (node->child);
201 * 'mxmlWalkNext()' - Walk to the next logical node in the tree.
203 * The descend argument controls whether the first child is considered
204 * to be the next node. The top node argument constrains the walk to
205 * the node's children.
208 mxml_node_t * /* O - Next node or NULL */
209 mxmlWalkNext(mxml_node_t *node, /* I - Current node */
210 mxml_node_t *top, /* I - Top node */
211 int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */
215 else if (node->child && descend)
216 return (node->child);
217 else if (node == top)
221 else if (node->parent && node->parent != top)
226 if (node->parent == top || !node->parent)
239 * 'mxmlWalkPrev()' - Walk to the previous logical node in the tree.
241 * The descend argument controls whether the previous node's last child
242 * is considered to be the previous node. The top node argument constrains
243 * the walk to the node's children.
246 mxml_node_t * /* O - Previous node or NULL */
247 mxmlWalkPrev(mxml_node_t *node, /* I - Current node */
248 mxml_node_t *top, /* I - Top node */
249 int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */
251 if (!node || node == top)
255 if (node->prev->last_child && descend)
258 * Find the last child under the previous node...
261 node = node->prev->last_child;
263 while (node->last_child)
264 node = node->last_child;
271 else if (node->parent != top)
272 return (node->parent);
279 * End of "$Id: mxml-search.c 451 2014-01-04 21:50:06Z msweet $".