This source file includes following definitions.
- freeXpathObject
- getXpathResult
- dedupXpathResults
- xpath_search
- crm_foreach_xpath_result
- get_xpath_object_relative
- get_xpath_object
- pcmk__element_xpath
- xml_get_path
- pcmk__xpath_node_id
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <crm/msg_xml.h>
14 #include <crm/common/xml_internal.h>
15 #include "crmcommon_private.h"
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 void
39 freeXpathObject(xmlXPathObjectPtr xpathObj)
40 {
41 int lpc, max = numXpathResults(xpathObj);
42
43 if (xpathObj == NULL) {
44 return;
45 }
46
47 for (lpc = 0; lpc < max; lpc++) {
48 if (xpathObj->nodesetval->nodeTab[lpc] && xpathObj->nodesetval->nodeTab[lpc]->type != XML_NAMESPACE_DECL) {
49 xpathObj->nodesetval->nodeTab[lpc] = NULL;
50 }
51 }
52
53
54 xmlXPathFreeObject(xpathObj);
55 }
56
57 xmlNode *
58 getXpathResult(xmlXPathObjectPtr xpathObj, int index)
59 {
60 xmlNode *match = NULL;
61 int max = numXpathResults(xpathObj);
62
63 CRM_CHECK(index >= 0, return NULL);
64 CRM_CHECK(xpathObj != NULL, return NULL);
65
66 if (index >= max) {
67 crm_err("Requested index %d of only %d items", index, max);
68 return NULL;
69
70 } else if(xpathObj->nodesetval->nodeTab[index] == NULL) {
71
72 return NULL;
73 }
74
75 match = xpathObj->nodesetval->nodeTab[index];
76 CRM_CHECK(match != NULL, return NULL);
77
78 if (xpathObj->nodesetval->nodeTab[index]->type != XML_NAMESPACE_DECL) {
79
80 xpathObj->nodesetval->nodeTab[index] = NULL;
81 }
82
83 if (match->type == XML_DOCUMENT_NODE) {
84
85 match = match->children;
86
87 } else if (match->type != XML_ELEMENT_NODE
88 && match->parent && match->parent->type == XML_ELEMENT_NODE) {
89
90 match = match->parent;
91
92 } else if (match->type != XML_ELEMENT_NODE) {
93
94 crm_err("We only support %d not %d", XML_ELEMENT_NODE, match->type);
95 match = NULL;
96 }
97 return match;
98 }
99
100 void
101 dedupXpathResults(xmlXPathObjectPtr xpathObj)
102 {
103 int lpc, max = numXpathResults(xpathObj);
104
105 if (xpathObj == NULL) {
106 return;
107 }
108
109 for (lpc = 0; lpc < max; lpc++) {
110 xmlNode *xml = NULL;
111 gboolean dedup = FALSE;
112
113 if (xpathObj->nodesetval->nodeTab[lpc] == NULL) {
114 continue;
115 }
116
117 xml = xpathObj->nodesetval->nodeTab[lpc]->parent;
118
119 for (; xml; xml = xml->parent) {
120 int lpc2 = 0;
121
122 for (lpc2 = 0; lpc2 < max; lpc2++) {
123 if (xpathObj->nodesetval->nodeTab[lpc2] == xml) {
124 xpathObj->nodesetval->nodeTab[lpc] = NULL;
125 dedup = TRUE;
126 break;
127 }
128 }
129
130 if (dedup) {
131 break;
132 }
133 }
134 }
135 }
136
137
138 xmlXPathObjectPtr
139 xpath_search(xmlNode * xml_top, const char *path)
140 {
141 xmlDocPtr doc = NULL;
142 xmlXPathObjectPtr xpathObj = NULL;
143 xmlXPathContextPtr xpathCtx = NULL;
144 const xmlChar *xpathExpr = (pcmkXmlStr) path;
145
146 CRM_CHECK(path != NULL, return NULL);
147 CRM_CHECK(xml_top != NULL, return NULL);
148 CRM_CHECK(strlen(path) > 0, return NULL);
149
150 doc = getDocPtr(xml_top);
151
152 xpathCtx = xmlXPathNewContext(doc);
153 CRM_ASSERT(xpathCtx != NULL);
154
155 xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
156 xmlXPathFreeContext(xpathCtx);
157 return xpathObj;
158 }
159
160
161
162
163
164
165
166
167
168
169
170
171
172 void
173 crm_foreach_xpath_result(xmlNode *xml, const char *xpath,
174 void (*helper)(xmlNode*, void*), void *user_data)
175 {
176 xmlXPathObjectPtr xpathObj = xpath_search(xml, xpath);
177 int nresults = numXpathResults(xpathObj);
178 int i;
179
180 for (i = 0; i < nresults; i++) {
181 xmlNode *result = getXpathResult(xpathObj, i);
182
183 CRM_LOG_ASSERT(result != NULL);
184 if (result) {
185 (*helper)(result, user_data);
186 }
187 }
188 freeXpathObject(xpathObj);
189 }
190
191 xmlNode *
192 get_xpath_object_relative(const char *xpath, xmlNode * xml_obj, int error_level)
193 {
194 xmlNode *result = NULL;
195 char *xpath_full = NULL;
196 char *xpath_prefix = NULL;
197
198 if (xml_obj == NULL || xpath == NULL) {
199 return NULL;
200 }
201
202 xpath_prefix = (char *)xmlGetNodePath(xml_obj);
203
204 xpath_full = crm_strdup_printf("%s%s", xpath_prefix, xpath);
205
206 result = get_xpath_object(xpath_full, xml_obj, error_level);
207
208 free(xpath_prefix);
209 free(xpath_full);
210 return result;
211 }
212
213 xmlNode *
214 get_xpath_object(const char *xpath, xmlNode * xml_obj, int error_level)
215 {
216 int max;
217 xmlNode *result = NULL;
218 xmlXPathObjectPtr xpathObj = NULL;
219 char *nodePath = NULL;
220 char *matchNodePath = NULL;
221
222 if (xpath == NULL) {
223 return xml_obj;
224 }
225
226 xpathObj = xpath_search(xml_obj, xpath);
227 nodePath = (char *)xmlGetNodePath(xml_obj);
228 max = numXpathResults(xpathObj);
229
230 if (max < 1) {
231 if (error_level < LOG_NEVER) {
232 do_crm_log(error_level, "No match for %s in %s",
233 xpath, crm_str(nodePath));
234 crm_log_xml_explicit(xml_obj, "Unexpected Input");
235 }
236
237 } else if (max > 1) {
238 if (error_level < LOG_NEVER) {
239 int lpc = 0;
240
241 do_crm_log(error_level, "Too many matches for %s in %s",
242 xpath, crm_str(nodePath));
243
244 for (lpc = 0; lpc < max; lpc++) {
245 xmlNode *match = getXpathResult(xpathObj, lpc);
246
247 CRM_LOG_ASSERT(match != NULL);
248 if (match != NULL) {
249 matchNodePath = (char *) xmlGetNodePath(match);
250 do_crm_log(error_level, "%s[%d] = %s",
251 xpath, lpc, crm_str(matchNodePath));
252 free(matchNodePath);
253 }
254 }
255 crm_log_xml_explicit(xml_obj, "Bad Input");
256 }
257
258 } else {
259 result = getXpathResult(xpathObj, 0);
260 }
261
262 freeXpathObject(xpathObj);
263 free(nodePath);
264
265 return result;
266 }
267
268 int
269 pcmk__element_xpath(const char *prefix, xmlNode *xml, char *buffer,
270 int offset, size_t buffer_size)
271 {
272 const char *id = ID(xml);
273
274 if(offset == 0 && prefix == NULL && xml->parent) {
275 offset = pcmk__element_xpath(NULL, xml->parent, buffer, offset,
276 buffer_size);
277 }
278
279 if(id) {
280 offset += snprintf(buffer + offset, buffer_size - offset,
281 "/%s[@id='%s']", (const char *) xml->name, id);
282 } else if(xml->name) {
283 offset += snprintf(buffer + offset, buffer_size - offset,
284 "/%s", (const char *) xml->name);
285 }
286
287 return offset;
288 }
289
290 char *
291 xml_get_path(xmlNode *xml)
292 {
293 int offset = 0;
294 char buffer[PCMK__BUFFER_SIZE];
295
296 if (pcmk__element_xpath(NULL, xml, buffer, offset, sizeof(buffer)) > 0) {
297 return strdup(buffer);
298 }
299 return NULL;
300 }
301
302 char *
303 pcmk__xpath_node_id(const char *xpath, const char *node)
304 {
305 char *retval = NULL;
306 char *patt = NULL;
307 char *start = NULL;
308 char *end = NULL;
309
310 if (node == NULL || xpath == NULL) {
311 return retval;
312 }
313
314 patt = crm_strdup_printf("/%s[@id=", node);
315 start = strstr(xpath, patt);
316
317 if (!start) {
318 free(patt);
319 return retval;
320 }
321
322 start += strlen(patt);
323 start++;
324
325 end = strstr(start, "\'");
326 CRM_ASSERT(end);
327 retval = strndup(start, end-start);
328
329 free(patt);
330 return retval;
331 }