1
1
#define _POSIX_C_SOURCE 200809L
2
+ #include <assert.h>
2
3
#include <ctype.h>
4
+ #include <glib.h>
3
5
#include <libxml/parser.h>
4
6
#include <libxml/tree.h>
7
+ #include <libxml/xpath.h>
8
+ #include <libxml/xpathInternals.h>
5
9
#include <stdbool.h>
6
10
#include <stdio.h>
11
+ #include <stdlib.h>
7
12
#include <string.h>
8
13
#include <strings.h>
14
+ #include <unistd.h>
9
15
10
16
static struct ctx {
11
17
char * filename ;
12
18
xmlDoc * doc ;
19
+ xmlXPathContextPtr xpath_ctx_ptr ;
13
20
char * nodename ;
14
21
char * value ;
15
22
enum {
@@ -140,7 +147,12 @@ xml_init(const char *filename)
140
147
ctx .filename = strdup (filename );
141
148
ctx .doc = xmlReadFile (filename , NULL , 0 );
142
149
if (!ctx .doc ) {
143
- fprintf (stderr , "Failed to parse %s\n" , filename );
150
+ fprintf (stderr , "warn: xmlReadFile('%s')\n" , filename );
151
+ }
152
+ ctx .xpath_ctx_ptr = xmlXPathNewContext (ctx .doc );
153
+ if (!ctx .xpath_ctx_ptr ) {
154
+ fprintf (stderr , "warn: xmlXPathNewContext()\n" );
155
+ xmlFreeDoc (ctx .doc );
144
156
}
145
157
}
146
158
@@ -153,6 +165,7 @@ xml_save(void)
153
165
void
154
166
xml_finish (void )
155
167
{
168
+ xmlXPathFreeContext (ctx .xpath_ctx_ptr );
156
169
xmlFreeDoc (ctx .doc );
157
170
xmlCleanupParser ();
158
171
}
@@ -212,3 +225,98 @@ xml_get_bool_text(char *nodename)
212
225
return -1 ;
213
226
}
214
227
}
228
+
229
+ char *
230
+ xml_get_content (char * xpath_expr )
231
+ {
232
+ xmlChar * ret = NULL ;
233
+ xmlXPathObjectPtr object = xmlXPathEvalExpression ((xmlChar * )xpath_expr , ctx .xpath_ctx_ptr );
234
+ if (!object ) {
235
+ fprintf (stderr , "warn: xmlXPathEvalExpression()\n" );
236
+ return NULL ;
237
+ }
238
+ if (!object -> nodesetval ) {
239
+ fprintf (stderr , "warn: no nodesetval\n" );
240
+ goto out ;
241
+ }
242
+ for (int i = 0 ; i < object -> nodesetval -> nodeNr ; i ++ ) {
243
+ if (!object -> nodesetval -> nodeTab [i ]) {
244
+ continue ;
245
+ }
246
+
247
+ /* Just grab the first node and go */
248
+ ret = xmlNodeGetContent (object -> nodesetval -> nodeTab [i ]);
249
+ goto out ;
250
+
251
+ /*
252
+ * We could process the node here and do things like:
253
+ * xmlNode *children = object->nodesetval->nodeTab[i]->children;
254
+ * for (xmlNode *cur = children; cur; cur = cur->next) { }
255
+ */
256
+ }
257
+
258
+ out :
259
+ xmlXPathFreeObject (object );
260
+ return (char * )ret ;
261
+ }
262
+
263
+ static xmlNode *
264
+ get_node (xmlChar * expr )
265
+ {
266
+ xmlNode * ret = NULL ;
267
+ xmlXPathObjectPtr object = xmlXPathEvalExpression (expr , ctx .xpath_ctx_ptr );
268
+ if (!object ) {
269
+ fprintf (stderr , "warn: xmlXPathEvalExpression()\n" );
270
+ return NULL ;
271
+ }
272
+ if (!object -> nodesetval ) {
273
+ fprintf (stderr , "warn: no nodesetval\n" );
274
+ goto out2 ;
275
+ }
276
+
277
+ for (int i = 0 ; i < object -> nodesetval -> nodeNr ; i ++ ) {
278
+ if (!object -> nodesetval -> nodeTab [i ]) {
279
+ continue ;
280
+ }
281
+ ret = object -> nodesetval -> nodeTab [i ];
282
+ break ;
283
+ }
284
+ out2 :
285
+ xmlXPathFreeObject (object );
286
+ return ret ;
287
+ }
288
+
289
+ void
290
+ xml_add_node (char * xpath_expr )
291
+ {
292
+ /* find existing parent */
293
+ char * parent_expr = strdup (xpath_expr );
294
+ xmlNode * parent_node = NULL ;
295
+ while (parent_expr && * parent_expr ) {
296
+ parent_node = get_node ((xmlChar * )parent_expr );
297
+ if (parent_node ) {
298
+ break ;
299
+ }
300
+ char * p = strrchr (parent_expr , '/' );
301
+ if (p && * p ) {
302
+ * p = '\0' ;
303
+ } else {
304
+ break ;
305
+ }
306
+ }
307
+ assert (parent_expr );
308
+ if (!* parent_expr ) {
309
+ /* the whole xpath expression is new, so add to root */
310
+ parent_node = xmlDocGetRootElement (ctx .doc );
311
+ }
312
+
313
+ /* add new nodes */
314
+ gchar * * nodes = g_strsplit (xpath_expr + strlen (parent_expr ), "/" , -1 );
315
+ for (gchar * * s = nodes ; * s ; s ++ ) {
316
+ if (* s && * * s ) {
317
+ parent_node = xmlNewChild (parent_node , NULL , (xmlChar * )* s , NULL );
318
+ }
319
+ }
320
+ g_free (parent_expr );
321
+ g_strfreev (nodes );
322
+ }
0 commit comments