Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 andreas 1
/*
2
 * Search/navigation functions for Mini-XML, a small XML file parsing library.
3
 *
4
 * https://www.msweet.org/mxml
5
 *
6
 * Copyright © 2003-2019 by Michael R Sweet.
7
 *
8
 * Licensed under Apache License v2.0.  See the file "LICENSE" for more
9
 * information.
10
 */
11
 
12
/*
13
 * Include necessary headers...
14
 */
15
 
16
#include "config.h"
17
#include "mxml-private.h"
18
 
19
 
20
/*
21
 * 'mxmlFindElement()' - Find the named element.
22
 *
23
 * The search is constrained by the name, attribute name, and value; any
24
 * @code NULL@ names or values are treated as wildcards, so different kinds of
25
 * searches can be implemented by looking for all elements of a given name
26
 * or all elements with a specific attribute. The descend argument determines
27
 * whether the search descends into child nodes; normally you will use
28
 * @code MXML_DESCEND_FIRST@ for the initial search and @code MXML_NO_DESCEND@
29
 * to find additional direct descendents of the node. The top node argument
30
 * constrains the search to a particular node's children.
31
 */
32
 
33
mxml_node_t *				/* O - Element node or @code NULL@ */
34
mxmlFindElement(mxml_node_t *node,	/* I - Current node */
35
                mxml_node_t *top,	/* I - Top node */
36
                const char  *element,	/* I - Element name or @code NULL@ for any */
37
		const char  *attr,	/* I - Attribute name, or @code NULL@ for none */
38
		const char  *value,	/* I - Attribute value, or @code NULL@ for any */
39
		int         descend)	/* I - Descend into tree - @code MXML_DESCEND@, @code MXML_NO_DESCEND@, or @code MXML_DESCEND_FIRST@ */
40
{
41
  const char	*temp;			/* Current attribute value */
42
 
43
 
44
 /*
45
  * Range check input...
46
  */
47
 
48
  if (!node || !top || (!attr && value))
49
    return (NULL);
50
 
51
 /*
52
  * Start with the next node...
53
  */
54
 
55
  node = mxmlWalkNext(node, top, descend);
56
 
57
 /*
58
  * Loop until we find a matching element...
59
  */
60
 
61
  while (node != NULL)
62
  {
63
   /*
64
    * See if this node matches...
65
    */
66
 
67
    if (node->type == MXML_ELEMENT &&
68
        node->value.element.name &&
69
	(!element || !strcmp(node->value.element.name, element)))
70
    {
71
     /*
72
      * See if we need to check for an attribute...
73
      */
74
 
75
      if (!attr)
76
        return (node);			/* No attribute search, return it... */
77
 
78
     /*
79
      * Check for the attribute...
80
      */
81
 
82
      if ((temp = mxmlElementGetAttr(node, attr)) != NULL)
83
      {
84
       /*
85
        * OK, we have the attribute, does it match?
86
	*/
87
 
88
	if (!value || !strcmp(value, temp))
89
	  return (node);		/* Yes, return it... */
90
      }
91
    }
92
 
93
   /*
94
    * No match, move on to the next node...
95
    */
96
 
97
    if (descend == MXML_DESCEND)
98
      node = mxmlWalkNext(node, top, MXML_DESCEND);
99
    else
100
      node = node->next;
101
  }
102
 
103
  return (NULL);
104
}
105
 
106
 
107
/*
108
 * 'mxmlFindPath()' - Find a node with the given path.
109
 *
110
 * The "path" is a slash-separated list of element names. The name "*" is
111
 * considered a wildcard for one or more levels of elements.  For example,
112
 * "foo/one/two", "bar/two/one", "*\/one", and so forth.
113
 *
114
 * The first child node of the found node is returned if the given node has
115
 * children and the first child is a value node.
116
 *
117
 * @since Mini-XML 2.7@
118
 */
119
 
120
mxml_node_t *				/* O - Found node or @code NULL@ */
121
mxmlFindPath(mxml_node_t *top,		/* I - Top node */
122
	     const char  *path)		/* I - Path to element */
123
{
124
  mxml_node_t	*node;			/* Current node */
125
  char		element[256];		/* Current element name */
126
  const char	*pathsep;		/* Separator in path */
127
  int		descend;		/* mxmlFindElement option */
128
 
129
 
130
 /*
131
  * Range check input...
132
  */
133
 
134
  if (!top || !path || !*path)
135
    return (NULL);
136
 
137
 /*
138
  * Search each element in the path...
139
  */
140
 
141
  node = top;
142
  while (*path)
143
  {
144
   /*
145
    * Handle wildcards...
146
    */
147
 
148
    if (!strncmp(path, "*/", 2))
149
    {
150
      path += 2;
151
      descend = MXML_DESCEND;
152
    }
153
    else
154
      descend = MXML_DESCEND_FIRST;
155
 
156
   /*
157
    * Get the next element in the path...
158
    */
159
 
160
    if ((pathsep = strchr(path, '/')) == NULL)
161
      pathsep = path + strlen(path);
162
 
163
    if (pathsep == path || (unsigned long)(pathsep - path) >= sizeof(element))
164
      return (NULL);
165
 
166
    memcpy(element, path, pathsep - path);
167
    element[pathsep - path] = '\0';
168
 
169
    if (*pathsep)
170
      path = pathsep + 1;
171
    else
172
      path = pathsep;
173
 
174
   /*
175
    * Search for the element...
176
    */
177
 
178
    if ((node = mxmlFindElement(node, node, element, NULL, NULL,
179
                                descend)) == NULL)
180
      return (NULL);
181
  }
182
 
183
 /*
184
  * If we get this far, return the node or its first child...
185
  */
186
 
187
  if (node->child && node->child->type != MXML_ELEMENT)
188
    return (node->child);
189
  else
190
    return (node);
191
}
192
 
193
 
194
/*
195
 * 'mxmlWalkNext()' - Walk to the next logical node in the tree.
196
 *
197
 * The descend argument controls whether the first child is considered
198
 * to be the next node.  The top node argument constrains the walk to
199
 * the node's children.
200
 */
201
 
202
mxml_node_t *				/* O - Next node or @code NULL@ */
203
mxmlWalkNext(mxml_node_t *node,		/* I - Current node */
204
             mxml_node_t *top,		/* I - Top node */
205
             int         descend)	/* I - Descend into tree - @code MXML_DESCEND@, @code MXML_NO_DESCEND@, or @code MXML_DESCEND_FIRST@ */
206
{
207
  if (!node)
208
    return (NULL);
209
  else if (node->child && descend)
210
    return (node->child);
211
  else if (node == top)
212
    return (NULL);
213
  else if (node->next)
214
    return (node->next);
215
  else if (node->parent && node->parent != top)
216
  {
217
    node = node->parent;
218
 
219
    while (!node->next)
220
      if (node->parent == top || !node->parent)
221
        return (NULL);
222
      else
223
        node = node->parent;
224
 
225
    return (node->next);
226
  }
227
  else
228
    return (NULL);
229
}
230
 
231
 
232
/*
233
 * 'mxmlWalkPrev()' - Walk to the previous logical node in the tree.
234
 *
235
 * The descend argument controls whether the previous node's last child
236
 * is considered to be the previous node.  The top node argument constrains
237
 * the walk to the node's children.
238
 */
239
 
240
mxml_node_t *				/* O - Previous node or @code NULL@ */
241
mxmlWalkPrev(mxml_node_t *node,		/* I - Current node */
242
             mxml_node_t *top,		/* I - Top node */
243
             int         descend)	/* I - Descend into tree - @code MXML_DESCEND@, @code MXML_NO_DESCEND@, or @code MXML_DESCEND_FIRST@ */
244
{
245
  if (!node || node == top)
246
    return (NULL);
247
  else if (node->prev)
248
  {
249
    if (node->prev->last_child && descend)
250
    {
251
     /*
252
      * Find the last child under the previous node...
253
      */
254
 
255
      node = node->prev->last_child;
256
 
257
      while (node->last_child)
258
        node = node->last_child;
259
 
260
      return (node);
261
    }
262
    else
263
      return (node->prev);
264
  }
265
  else if (node->parent != top)
266
    return (node->parent);
267
  else
268
    return (NULL);
269
}