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