comparison src/xmlnode.c @ 13806:25e63008d3bb

[gaim-migrate @ 16229] Use libxml2 for XML parsing, if available. The biggest benefit from this is actual support for XML namespaces. This fixes a handful of Google Talk integration problems, including typing notifications and buddy icons. committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Thu, 08 Jun 2006 01:03:51 +0000
parents 02833a0ae716
children 3c6d0c24179a
comparison
equal deleted inserted replaced
13805:853fefb07c79 13806:25e63008d3bb
27 * write my own stuff. Also, re-writing this lets me be as lightweight 27 * write my own stuff. Also, re-writing this lets me be as lightweight
28 * as I want to be. Thank you libxode for giving me a good starting point */ 28 * as I want to be. Thank you libxode for giving me a good starting point */
29 29
30 #include "internal.h" 30 #include "internal.h"
31 31
32 #ifdef HAVE_LIBXML
33 #include <libxml/parser.h>
34 #endif
32 #include <string.h> 35 #include <string.h>
33 #include <glib.h> 36 #include <glib.h>
34 37
35 #include "xmlnode.h" 38 #include "xmlnode.h"
36 39
170 } 173 }
171 174
172 return NULL; 175 return NULL;
173 } 176 }
174 177
178
179 void xmlnode_set_namespace(xmlnode *node, const char *xmlns)
180 {
181 #ifdef HAVE_LIBXML
182 g_return_if_fail(node != NULL);
183
184 if (node->namespace)
185 g_free(node->namespace);
186
187 node->namespace = g_strdup(xmlns);
188 #else
189 return xmlnode_set_attrib(node, "xmlns", xmlns);
190 #endif
191 }
192
193 const char *xmlnode_get_namespace(xmlnode *node)
194 {
195 #ifdef HAVE_LIBXML
196 g_return_val_if_fail(node != NULL, NULL);
197
198 return node->namespace;
199 #else
200 return xmlnode_get_attrib(node, "xmlns");
201 #endif
202 }
203
175 void 204 void
176 xmlnode_free(xmlnode *node) 205 xmlnode_free(xmlnode *node)
177 { 206 {
178 xmlnode *x, *y; 207 xmlnode *x, *y;
179 208
188 217
189 if(node->name) 218 if(node->name)
190 g_free(node->name); 219 g_free(node->name);
191 if(node->data) 220 if(node->data)
192 g_free(node->data); 221 g_free(node->data);
222 #ifdef HAVE_LIBXML
223 if(node->namespace)
224 g_free(node->namespace);
225 #endif
193 g_free(node); 226 g_free(node);
194 } 227 }
195 228
196 xmlnode* 229 xmlnode*
197 xmlnode_get_child(const xmlnode *parent, const char *name) 230 xmlnode_get_child(const xmlnode *parent, const char *name)
214 child_name = names[1]; 247 child_name = names[1];
215 248
216 for(x = parent->child; x; x = x->next) { 249 for(x = parent->child; x; x = x->next) {
217 const char *xmlns = NULL; 250 const char *xmlns = NULL;
218 if(ns) 251 if(ns)
219 xmlns = xmlnode_get_attrib(x, "xmlns"); 252 xmlns = xmlnode_get_namespace(x);
220 253
221 if(x->type == XMLNODE_TYPE_TAG && name && !strcmp(parent_name, x->name) 254 if(x->type == XMLNODE_TYPE_TAG && name && !strcmp(parent_name, x->name)
222 && (!ns || (xmlns && !strcmp(ns, xmlns)))) { 255 && (!ns || (xmlns && !strcmp(ns, xmlns)))) {
223 ret = x; 256 ret = x;
224 break; 257 break;
270 } 303 }
271 304
272 node_name = g_markup_escape_text(node->name, -1); 305 node_name = g_markup_escape_text(node->name, -1);
273 g_string_append_printf(text, "<%s", node_name); 306 g_string_append_printf(text, "<%s", node_name);
274 307
308 #ifdef HAVE_LIBXML
309 if (node->namespace) {
310 char *namespace = g_markup_escape_text(node->namespace, -1);
311 g_string_append_printf(text, " xmlns='%s'", namespace);
312 g_free(namespace);
313 }
314 #endif
275 for(c = node->child; c; c = c->next) 315 for(c = node->child; c; c = c->next)
276 { 316 {
277 if(c->type == XMLNODE_TYPE_ATTRIB) { 317 if(c->type == XMLNODE_TYPE_ATTRIB) {
278 esc = g_markup_escape_text(c->name, -1); 318 esc = g_markup_escape_text(c->name, -1);
279 esc2 = g_markup_escape_text(c->data, -1); 319 esc2 = g_markup_escape_text(c->data, -1);
345 385
346 struct _xmlnode_parser_data { 386 struct _xmlnode_parser_data {
347 xmlnode *current; 387 xmlnode *current;
348 }; 388 };
349 389
390 #ifdef HAVE_LIBXML
350 static void 391 static void
351 xmlnode_parser_element_start(GMarkupParseContext *context, 392 xmlnode_parser_element_start_libxml(void *user_data,
352 const char *element_name, const char **attrib_names, 393 const xmlChar *element_name, const xmlChar *prefix, const xmlChar *namespace,
353 const char **attrib_values, gpointer user_data, GError **error) 394 int nb_namespaces, const xmlChar **namespaces,
395 int nb_attributes, int nb_defaulted, const xmlChar **attributes)
354 { 396 {
355 struct _xmlnode_parser_data *xpd = user_data; 397 struct _xmlnode_parser_data *xpd = user_data;
356 xmlnode *node; 398 xmlnode *node;
357 int i; 399 int i;
358 400
362 if(xpd->current) 404 if(xpd->current)
363 node = xmlnode_new_child(xpd->current, element_name); 405 node = xmlnode_new_child(xpd->current, element_name);
364 else 406 else
365 node = xmlnode_new(element_name); 407 node = xmlnode_new(element_name);
366 408
409 xmlnode_set_namespace(node, namespace);
410
411 for(i=0; i < nb_attributes * 5; i+=5) {
412 int attrib_len = attributes[i+4] - attributes[i+3];
413 char *attrib = g_malloc(attrib_len + 1);
414 memcpy(attrib, attributes[i+3], attrib_len);
415 attrib[attrib_len] = '\0';
416 xmlnode_set_attrib(node, attributes[i], attrib);
417 g_free(attrib);
418 }
419
420 xpd->current = node;
421 }
422 }
423
424 static void
425 xmlnode_parser_element_end_libxml(void *user_data, const xmlChar *element_name,
426 const xmlChar *prefix, const xmlChar *namespace)
427 {
428 struct _xmlnode_parser_data *xpd = user_data;
429
430 if(!element_name || !xpd->current)
431 return;
432
433 if(xpd->current->parent) {
434 if(!strcmp(xpd->current->name, element_name))
435 xpd->current = xpd->current->parent;
436 }
437 }
438
439 static void
440 xmlnode_parser_element_text_libxml(void *user_data, const xmlChar *text, int text_len)
441 {
442 struct _xmlnode_parser_data *xpd = user_data;
443
444 if(!xpd->current)
445 return;
446
447 if(!text || !text_len)
448 return;
449
450 xmlnode_insert_data(xpd->current, text, text_len);
451 }
452
453 #else
454
455 static void
456 xmlnode_parser_element_start(GMarkupParseContext *context,
457 const char *element_name, const char **attrib_names,
458 const char **attrib_values, gpointer user_data, GError **error)
459 {
460 struct _xmlnode_parser_data *xpd = user_data;
461 xmlnode *node;
462 int i;
463
464 if(!element_name) {
465 return;
466 } else {
467 if(xpd->current)
468 node = xmlnode_new_child(xpd->current, element_name);
469 else
470 node = xmlnode_new(element_name);
471
367 for(i=0; attrib_names[i]; i++) 472 for(i=0; attrib_names[i]; i++)
368 xmlnode_set_attrib(node, attrib_names[i], attrib_values[i]); 473 xmlnode_set_attrib(node, attrib_names[i], attrib_values[i]);
369 474
370 xpd->current = node; 475 xpd->current = node;
371 } 476 }
398 if(!text || !text_len) 503 if(!text || !text_len)
399 return; 504 return;
400 505
401 xmlnode_insert_data(xpd->current, text, text_len); 506 xmlnode_insert_data(xpd->current, text, text_len);
402 } 507 }
403 508 #endif
509
510 #ifdef HAVE_LIBXML
511 static xmlSAXHandler xmlnode_parser_libxml = {
512 .internalSubset = NULL,
513 .isStandalone = NULL,
514 .hasInternalSubset = NULL,
515 .hasExternalSubset = NULL,
516 .resolveEntity = NULL,
517 .getEntity = NULL,
518 .entityDecl = NULL,
519 .notationDecl = NULL,
520 .attributeDecl = NULL,
521 .elementDecl = NULL,
522 .unparsedEntityDecl = NULL,
523 .setDocumentLocator = NULL,
524 .startDocument = NULL,
525 .endDocument = NULL,
526 .startElement = NULL,
527 .endElement = NULL,
528 .reference = NULL,
529 .characters = xmlnode_parser_element_text_libxml,
530 .ignorableWhitespace = NULL,
531 .processingInstruction = NULL,
532 .comment = NULL,
533 .warning = NULL,
534 .error = NULL,
535 .fatalError = NULL,
536 .getParameterEntity = NULL,
537 .cdataBlock = NULL,
538 .externalSubset = NULL,
539 .initialized = XML_SAX2_MAGIC,
540 ._private = NULL,
541 .startElementNs = xmlnode_parser_element_start_libxml,
542 .endElementNs = xmlnode_parser_element_end_libxml,
543 .serror = NULL
544 };
545 #else
404 static GMarkupParser xmlnode_parser = { 546 static GMarkupParser xmlnode_parser = {
405 xmlnode_parser_element_start, 547 xmlnode_parser_element_start,
406 xmlnode_parser_element_end, 548 xmlnode_parser_element_end,
407 xmlnode_parser_element_text, 549 xmlnode_parser_element_text,
408 NULL, 550 NULL,
409 NULL 551 NULL
410 }; 552 };
411 553 #endif
412 554
413 xmlnode * 555 xmlnode *
414 xmlnode_from_str(const char *str, gssize size) 556 xmlnode_from_str(const char *str, gssize size)
415 { 557 {
416 struct _xmlnode_parser_data *xpd; 558 struct _xmlnode_parser_data *xpd;
420 562
421 g_return_val_if_fail(str != NULL, NULL); 563 g_return_val_if_fail(str != NULL, NULL);
422 564
423 real_size = size < 0 ? strlen(str) : size; 565 real_size = size < 0 ? strlen(str) : size;
424 xpd = g_new0(struct _xmlnode_parser_data, 1); 566 xpd = g_new0(struct _xmlnode_parser_data, 1);
567
568 #ifdef HAVE_LIBXML
569 if (xmlSAXUserParseMemory(&xmlnode_parser_libxml, xpd, str, size) < 0) {
570 while(xpd->current && xpd->current->parent)
571 xpd->current = xpd->current->parent;
572 if(xpd->current)
573 xmlnode_free(xpd->current);
574 xpd->current = NULL;
575 }
576 #else
425 context = g_markup_parse_context_new(&xmlnode_parser, 0, xpd, NULL); 577 context = g_markup_parse_context_new(&xmlnode_parser, 0, xpd, NULL);
426 578
427 if(!g_markup_parse_context_parse(context, str, real_size, NULL)) { 579 if(!g_markup_parse_context_parse(context, str, real_size, NULL)) {
428 while(xpd->current && xpd->current->parent) 580 while(xpd->current && xpd->current->parent)
429 xpd->current = xpd->current->parent; 581 xpd->current = xpd->current->parent;
430 if(xpd->current) 582 if(xpd->current)
431 xmlnode_free(xpd->current); 583 xmlnode_free(xpd->current);
432 xpd->current = NULL; 584 xpd->current = NULL;
433 } 585 }
434 g_markup_parse_context_free(context); 586 g_markup_parse_context_free(context);
435 587 #endif
436 ret = xpd->current; 588 ret = xpd->current;
437 g_free(xpd); 589 g_free(xpd);
438 return ret; 590 return ret;
439 } 591 }
440 592
475 627
476 xmlnode * 628 xmlnode *
477 xmlnode_get_next_twin(xmlnode *node) 629 xmlnode_get_next_twin(xmlnode *node)
478 { 630 {
479 xmlnode *sibling; 631 xmlnode *sibling;
480 const char *ns = xmlnode_get_attrib(node, "xmlns"); 632 const char *ns = xmlnode_get_namespace(node);
481 633
482 g_return_val_if_fail(node != NULL, NULL); 634 g_return_val_if_fail(node != NULL, NULL);
483 g_return_val_if_fail(node->type == XMLNODE_TYPE_TAG, NULL); 635 g_return_val_if_fail(node->type == XMLNODE_TYPE_TAG, NULL);
484 636
485 for(sibling = node->next; sibling; sibling = sibling->next) { 637 for(sibling = node->next; sibling; sibling = sibling->next) {
486 const char *xmlns = NULL; 638 const char *xmlns = NULL;
487 if(ns) 639 if(ns)
488 xmlns = xmlnode_get_attrib(sibling, "xmlns"); 640 xmlns = xmlnode_get_namespace(sibling);
489 641
490 if(sibling->type == XMLNODE_TYPE_TAG && !strcmp(node->name, sibling->name) && 642 if(sibling->type == XMLNODE_TYPE_TAG && !strcmp(node->name, sibling->name) &&
491 (!ns || (xmlns && !strcmp(ns, xmlns)))) 643 (!ns || (xmlns && !strcmp(ns, xmlns))))
492 return sibling; 644 return sibling;
493 } 645 }