glade-xml-utils.c 23.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * glade-xml-utils.c - This functions are based on gnome-print/libgpa/gpa-xml.c
 * which were in turn based on gnumeric/xml-io.c
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
   *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * Authors:
Jose Maria Celorio's avatar
Jose Maria Celorio committed
20 21 22 23 24
 *   Daniel Veillard <Daniel.Veillard@w3.org>
 *   Miguel de Icaza <miguel@gnu.org>
 *   Chema Celorio <chema@gnome.org>
 */

25 26 27 28 29 30 31 32 33 34 35
/**
 * SECTION:glade-xml-utils
 * @Title: Xml Utils
 * @Short_Description: An api to read and write xml.
 *
 * You may need these tools if you are implementing #GladeReadWidgetFunc
 * and/or #GladeWriteWidgetFunc on your #GladeWidgetAdaptor to read
 * and write widgets in custom ways
 */


Christian Persch's avatar
Christian Persch committed
36 37
#include "config.h"

38
#include <string.h>
Jose Maria Celorio's avatar
Jose Maria Celorio committed
39
#include <glib.h>
40
#include <errno.h>
Jose Maria Celorio's avatar
Jose Maria Celorio committed
41 42

#include "glade-xml-utils.h"
43
#include "glade-catalog.h"
44
#include "glade-utils.h"
Jose Maria Celorio's avatar
Jose Maria Celorio committed
45

46 47 48 49 50 51 52
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/parserInternals.h>
#include <libxml/xmlmemory.h>

struct _GladeXmlNode
{
53
  xmlNodePtr node;
54 55 56 57
};

struct _GladeXmlDoc
{
58
  xmlDoc doc;
59 60
};

61 62 63 64 65
struct _GladeXmlContext
{
  GladeXmlDoc *doc;
  gboolean freedoc;
  xmlNsPtr ns;
66 67 68
};


69 70 71
/* This is used inside for loops so that we skip xml comments 
 * <!-- i am a comment ->
 * also to skip whitespace between nodes
72
 */
73 74
#define skip_text(node) if ((xmlStrcmp ( ((xmlNodePtr)node)->name, BAD_CAST("text")) == 0) ||\
			    (xmlStrcmp ( ((xmlNodePtr)node)->name, BAD_CAST("comment")) == 0)) { \
75
			         node = (GladeXmlNode *)((xmlNodePtr)node)->next; continue ; };
76 77
#define skip_text_libxml(node) if ((xmlStrcmp ( ((xmlNodePtr)node)->name, BAD_CAST("text")) == 0) ||\
			           (xmlStrcmp ( ((xmlNodePtr)node)->name, BAD_CAST("comment")) == 0)) { \
78 79
                                       node = ((xmlNodePtr)node)->next; continue ; };

80 81

static gchar *
82
claim_string (xmlChar *string)
83
{
84 85 86 87
  gchar *ret;
  ret = g_strdup (CAST_BAD (string));
  xmlFree (string);
  return ret;
88 89
}

90 91 92 93 94 95 96
/**
 * glade_xml_set_value:
 * @node_in: a #GladeXmlNode
 * @name: a string
 * @val: a string
 *
 * Sets the property @name in @node_in to @val
Jose Maria Celorio's avatar
Jose Maria Celorio committed
97 98
 */
void
99
glade_xml_set_value (GladeXmlNode *node_in, const gchar *name, const gchar *val)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
100
{
101 102
  xmlNodePtr node = (xmlNodePtr) node_in;
  xmlChar *ret;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
103

104 105 106 107 108 109 110
  ret = xmlGetProp (node, BAD_CAST (name));
  if (ret)
    {
      xmlFree (ret);
      xmlSetProp (node, BAD_CAST (name), BAD_CAST (val));
      return;
    }
Jose Maria Celorio's avatar
Jose Maria Celorio committed
111 112
}

113 114 115 116
/**
 * glade_xml_get_content:
 * @node_in: a #GladeXmlNode
 *
117 118 119
 * Gets a string containing the content of @node_in.
 *
 * Returns: A newly allocated string
120
 */
Jose Maria Celorio's avatar
Jose Maria Celorio committed
121
gchar *
122
glade_xml_get_content (GladeXmlNode *node_in)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
123
{
124 125
  xmlNodePtr node = (xmlNodePtr) node_in;
  xmlChar *val = xmlNodeGetContent (node);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
126

127
  return claim_string (val);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
128 129
}

130 131 132 133 134 135 136
/**
 * glade_xml_set_content:
 * @node_in: a #GladeXmlNode
 * @content: a string
 *
 * Sets the content of @node to @content.
 */
Chema Celorio's avatar
Chema Celorio committed
137
void
138
glade_xml_set_content (GladeXmlNode *node_in, const gchar *content)
Chema Celorio's avatar
Chema Celorio committed
139
{
140
  xmlNodePtr node = (xmlNodePtr) node_in;
141
  xmlChar *content_encoded;
Chema Celorio's avatar
Chema Celorio committed
142

143 144 145 146 147 148
  g_return_if_fail (node != NULL);
  g_return_if_fail (node->doc != NULL);

  content_encoded = xmlEncodeSpecialChars (node->doc, BAD_CAST (content));
  xmlNodeSetContent (node, BAD_CAST (content_encoded));
  xmlFree (content_encoded);
Chema Celorio's avatar
Chema Celorio committed
149 150
}

Jose Maria Celorio's avatar
Jose Maria Celorio committed
151 152 153 154 155 156 157 158
/*
 * Get a value for a node either carried as an attibute or as
 * the content of a child.
 *
 * Returns a g_malloc'ed string.  Caller must free.
 * (taken from gnumeric )
 *
 */
159
static gchar *
160
glade_xml_get_value (xmlNodePtr node, const gchar *name)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
161
{
162 163 164 165 166 167
  xmlNodePtr child;
  gchar *ret = NULL;

  for (child = node->children; child; child = child->next)
    if (!xmlStrcmp (child->name, BAD_CAST (name)))
      ret = claim_string (xmlNodeGetContent (child));
Jose Maria Celorio's avatar
Jose Maria Celorio committed
168

169
  return ret;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
170 171
}

172 173 174 175 176 177 178
/**
 * glade_xml_node_verify_silent:
 * @node_in: a #GladeXmlNode
 * @name: a string
 *
 * Returns: %TRUE if @node_in's name is equal to @name, %FALSE otherwise
 */
179
gboolean
180
glade_xml_node_verify_silent (GladeXmlNode *node_in, const gchar *name)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
181
{
182 183 184
  xmlNodePtr node = (xmlNodePtr) node_in;

  g_return_val_if_fail (node != NULL, FALSE);
Chema Celorio's avatar
Chema Celorio committed
185

186 187 188
  if (xmlStrcmp (node->name, BAD_CAST (name)) != 0)
    return FALSE;
  return TRUE;
189 190
}

191 192 193 194 195 196 197 198 199 200
/**
 * glade_xml_node_verify:
 * @node_in: a #GladeXmlNode
 * @name: a string
 *
 * This is a wrapper around glade_xml_node_verify_silent(), only it emits
 * a g_warning() if @node_in has a name different than @name.
 *
 * Returns: %TRUE if @node_in's name is equal to @name, %FALSE otherwise
 */
201
gboolean
202
glade_xml_node_verify (GladeXmlNode *node_in, const gchar *name)
203
{
204
  xmlNodePtr node = (xmlNodePtr) node_in;
205

206 207 208 209 210 211
  if (!glade_xml_node_verify_silent (node_in, name))
    {
      g_warning ("Expected node was \"%s\", encountered \"%s\"",
                 name, node->name);
      return FALSE;
    }
212

213
  return TRUE;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
214 215
}

216 217 218 219 220 221 222
/**
 * glade_xml_get_value_int:
 * @node_in: a #GladeXmlNode
 * @name: a string
 * @val: a pointer to an #int
 *
 * Gets an integer value for a node either carried as an attribute or as
Jose Maria Celorio's avatar
Jose Maria Celorio committed
223
 * the content of a child.
224 225
 *
 * Returns: %TRUE if the node is found, %FALSE otherwise
Jose Maria Celorio's avatar
Jose Maria Celorio committed
226 227
 */
gboolean
228
glade_xml_get_value_int (GladeXmlNode *node_in, const gchar *name, gint *val)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
229
{
230 231 232
  xmlNodePtr node = (xmlNodePtr) node_in;
  gchar *value, *endptr = NULL;
  gint64 i;
233

234 235 236
  value = glade_xml_get_value (node, name);
  if (value == NULL)
    return FALSE;
237

238 239 240 241 242 243 244
  errno = 0;
  i = g_ascii_strtoll (value, &endptr, 10);
  if (errno != 0 || (i == 0 && endptr == value))
    {
      g_free (value);
      return FALSE;
    }
245

246 247 248
  g_free (value);
  *val = (gint) i;
  return TRUE;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
249 250 251 252
}

/**
 * glade_xml_get_value_int_required:
253 254 255
 * @node: a #GladeXmlNode
 * @name: a string
 * @val: a pointer to an #int
Jose Maria Celorio's avatar
Jose Maria Celorio committed
256
 * 
257 258
 * This is a wrapper around glade_xml_get_value_int(), only it emits
 * a g_warning() if @node_in did not contain the requested tag
Jose Maria Celorio's avatar
Jose Maria Celorio committed
259
 * 
260
 * Returns:
Jose Maria Celorio's avatar
Jose Maria Celorio committed
261 262
 **/
gboolean
263 264 265
glade_xml_get_value_int_required (GladeXmlNode *node,
                                  const gchar  *name,
                                  gint         *val)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
266
{
267 268 269
  gboolean ret;

  ret = glade_xml_get_value_int (node, name, val);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
270

271 272 273 274 275
  if (ret == FALSE)
    g_warning ("The file did not contain the required value \"%s\"\n"
               "Under the \"%s\" tag.", name, glade_xml_node_get_name (node));

  return ret;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
276 277 278 279 280 281 282
}

/*
 * Get a String value for a node either carried as an attibute or as
 * the content of a child.
 */
gchar *
283
glade_xml_get_value_string (GladeXmlNode *node_in, const gchar *name)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
284
{
285 286
  xmlNodePtr node = (xmlNodePtr) node_in;
  return glade_xml_get_value (node, name);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
287 288
}

289
static gchar *
290
glade_xml_get_property (xmlNodePtr node, const gchar *name)
Chema Celorio's avatar
Chema Celorio committed
291
{
292
  xmlChar *val;
293

294
  val = xmlGetProp (node, BAD_CAST (name));
Chema Celorio's avatar
Chema Celorio committed
295

296 297
  if (val)
    return claim_string (val);
Chema Celorio's avatar
Chema Celorio committed
298

299
  return NULL;
Chema Celorio's avatar
Chema Celorio committed
300 301 302
}

static void
303 304 305
glade_xml_set_property (xmlNodePtr   node,
                        const gchar *name,
                        const gchar *value)
Chema Celorio's avatar
Chema Celorio committed
306
{
307 308
  if (value)
    xmlSetProp (node, BAD_CAST (name), BAD_CAST (value));
Chema Celorio's avatar
Chema Celorio committed
309 310
}

Jose Maria Celorio's avatar
Jose Maria Celorio committed
311 312 313 314 315
/*
 * Get a String value for a node either carried as an attibute or as
 * the content of a child.
 */
gboolean
316 317 318
glade_xml_get_boolean (GladeXmlNode *node_in,
                       const gchar  *name,
                       gboolean      _default)
319 320 321 322 323 324 325 326 327
{
  xmlNodePtr node = (xmlNodePtr) node_in;
  gchar *value;
  gboolean ret = FALSE;

  value = glade_xml_get_value (node, name);
  if (value == NULL)
    return _default;

328
  if (glade_utils_boolean_from_string (value, &ret))
329 330 331 332
    g_warning ("Boolean tag unrecognized *%s*\n", value);
  g_free (value);

  return ret;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
333
}
Chema Celorio's avatar
Chema Celorio committed
334 335 336 337 338 339

/*
 * Get a String value for a node either carried as an attibute or as
 * the content of a child.
 */
gboolean
340 341 342
glade_xml_get_property_boolean (GladeXmlNode *node_in,
                                const gchar  *name,
                                gboolean      _default)
343 344 345 346 347 348 349 350 351
{
  xmlNodePtr node = (xmlNodePtr) node_in;
  gchar *value;
  gboolean ret = FALSE;

  value = glade_xml_get_property (node, name);
  if (value == NULL)
    return _default;

352
  if (glade_utils_boolean_from_string (value, &ret))
353 354 355 356
    g_warning ("Boolean tag unrecognized *%s*\n", value);
  g_free (value);

  return ret;
Chema Celorio's avatar
Chema Celorio committed
357 358
}

359
gdouble
360 361 362
glade_xml_get_property_double (GladeXmlNode *node_in,
                               const gchar  *name,
                               gdouble       _default)
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
{
  xmlNodePtr node = (xmlNodePtr) node_in;
  gdouble retval;
  gchar *value;

  if ((value = glade_xml_get_property (node, name)) == NULL)
    return _default;

  errno = 0;

  retval = g_ascii_strtod (value, NULL);

  if (errno)
    {
      g_free (value);
      return _default;
    }
  else
    {
      g_free (value);
      return retval;
    }
385 386
}

387
gint
388 389 390
glade_xml_get_property_int (GladeXmlNode *node_in,
                            const gchar  *name,
                            gint          _default)
391
{
392 393 394 395 396 397 398 399
  xmlNodePtr node = (xmlNodePtr) node_in;
  gint retval;
  gchar *value;

  if ((value = glade_xml_get_property (node, name)) == NULL)
    return _default;

  retval = g_ascii_strtoll (value, NULL, 10);
400

401
  g_free (value);
402

403
  return retval;
404 405
}

406
void
407 408 409
glade_xml_node_set_property_boolean (GladeXmlNode *node_in,
                                     const gchar  *name,
                                     gboolean      value)
410
{
411
  xmlNodePtr node = (xmlNodePtr) node_in;
412

413
  if (value)
414
    glade_xml_set_property (node, name, "True");
415
  else
416
    glade_xml_set_property (node, name, "False");
417 418
}

Jose Maria Celorio's avatar
Jose Maria Celorio committed
419
gchar *
420 421 422
glade_xml_get_value_string_required (GladeXmlNode *node_in,
                                     const gchar  *name,
                                     const gchar  *xtra)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
423
{
424 425
  xmlNodePtr node = (xmlNodePtr) node_in;
  gchar *value = glade_xml_get_value (node, name);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
426

427 428 429 430 431 432 433 434 435
  if (value == NULL)
    {
      if (xtra == NULL)
        g_warning ("The file did not contain the required value \"%s\"\n"
                   "Under the \"%s\" tag.", name, node->name);
      else
        g_warning ("The file did not contain the required value \"%s\"\n"
                   "Under the \"%s\" tag (%s).", name, node->name, xtra);
    }
436

437
  return value;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
438 439
}

Chema Celorio's avatar
Chema Celorio committed
440
gchar *
441
glade_xml_get_property_string (GladeXmlNode *node_in, const gchar *name)
Chema Celorio's avatar
Chema Celorio committed
442
{
443
  xmlNodePtr node = (xmlNodePtr) node_in;
Chema Celorio's avatar
Chema Celorio committed
444

445
  return glade_xml_get_property (node, name);
Chema Celorio's avatar
Chema Celorio committed
446 447 448
}

void
449 450 451
glade_xml_node_set_property_string (GladeXmlNode *node_in,
                                    const gchar  *name,
                                    const gchar  *string)
Chema Celorio's avatar
Chema Celorio committed
452
{
453
  xmlNodePtr node = (xmlNodePtr) node_in;
Chema Celorio's avatar
Chema Celorio committed
454

455
  glade_xml_set_property (node, name, string);
Chema Celorio's avatar
Chema Celorio committed
456 457 458
}

gchar *
459 460 461
glade_xml_get_property_string_required (GladeXmlNode *node_in,
                                        const gchar  *name,
                                        const gchar  *xtra)
Chema Celorio's avatar
Chema Celorio committed
462
{
463 464
  xmlNodePtr node = (xmlNodePtr) node_in;
  gchar *value = glade_xml_get_property_string (node_in, name);
Chema Celorio's avatar
Chema Celorio committed
465

466 467 468 469 470 471 472 473 474 475
  if (value == NULL)
    {
      if (xtra == NULL)
        g_warning ("The file did not contain the required property \"%s\"\n"
                   "Under the \"%s\" tag.", name, node->name);
      else
        g_warning ("The file did not contain the required property \"%s\"\n"
                   "Under the \"%s\" tag (%s).", name, node->name, xtra);
    }
  return value;
Chema Celorio's avatar
Chema Celorio committed
476 477
}

478
gboolean
479 480 481 482
glade_xml_get_property_version (GladeXmlNode *node_in,
                                const gchar  *name,
                                guint16      *major,
                                guint16      * minor)
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
{
  xmlNodePtr node = (xmlNodePtr) node_in;
  gchar *value = glade_xml_get_property_string (node_in, name);
  gchar **split;

  if (!value)
    return FALSE;

  if ((split = g_strsplit (value, ".", 2)))
    {
      if (!split[0] || !split[1])
        {
          g_warning ("Malformed version property \"%s\"\n"
                     "Under the \"%s\" tag (%s)", name, node->name, value);
          return FALSE;
        }

      *major = g_ascii_strtoll (split[0], NULL, 10);
      *minor = g_ascii_strtoll (split[1], NULL, 10);

      g_strfreev (split);
    }
505 506 507

  g_free (value);

508
  return TRUE;
509 510 511
}

GList *
512 513
glade_xml_get_property_targetable_versions (GladeXmlNode *node_in,
                                            const gchar  *name)
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
{
  GladeTargetableVersion *version;
  GList *targetable = NULL;
  xmlNodePtr node = (xmlNodePtr) node_in;
  gchar *value;
  gchar **split, **maj_min;
  gint i;

  if (!(value = glade_xml_get_property_string (node_in, name)))
    return NULL;

  if ((split = g_strsplit (value, ",", 0)) != NULL)
    {
      for (i = 0; split[i]; i++)
        {
          maj_min = g_strsplit (split[i], ".", 2);

          if (!maj_min[0] || !maj_min[1])
            {
              g_warning ("Malformed version property \"%s\"\n"
                         "Under the \"%s\" tag (%s)", name, node->name, value);
            }
          else
            {
              version = g_new (GladeTargetableVersion, 1);
              version->major = g_ascii_strtoll (maj_min[0], NULL, 10);
              version->minor = g_ascii_strtoll (maj_min[1], NULL, 10);

              targetable = g_list_append (targetable, version);
            }
          g_strfreev (maj_min);
        }

      g_strfreev (split);
    }
549 550 551

  g_free (value);

552
  return targetable;
553 554 555 556
}



Jose Maria Celorio's avatar
Jose Maria Celorio committed
557 558 559
/*
 * Search a child by name,
 */
Chema Celorio's avatar
Chema Celorio committed
560
GladeXmlNode *
561
glade_xml_search_child (GladeXmlNode *node_in, const gchar *name)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
562
{
563 564
  xmlNodePtr node;
  xmlNodePtr child;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
565

566 567
  g_return_val_if_fail (node_in != NULL, NULL);
  g_return_val_if_fail (name != NULL, NULL);
568

569
  node = (xmlNodePtr) node_in;
570

571 572 573 574 575
  for (child = node->children; child; child = child->next)
    {
      if (!xmlStrcmp (child->name, BAD_CAST (name)))
        return (GladeXmlNode *) child;
    }
Jose Maria Celorio's avatar
Jose Maria Celorio committed
576

577
  return NULL;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
578 579 580 581 582 583 584
}

/**
 * glade_xml_search_child_required:
 * @tree: 
 * @name: 
 * 
585
 * just a small wrapper arround glade_xml_search_child that displays
Jose Maria Celorio's avatar
Jose Maria Celorio committed
586 587 588 589
 * an error if the child was not found
 *
 * Return Value: 
 **/
Chema Celorio's avatar
Chema Celorio committed
590
GladeXmlNode *
591
glade_xml_search_child_required (GladeXmlNode *node, const gchar *name)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
592
{
593
  GladeXmlNode *child;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
594

595
  child = glade_xml_search_child (node, name);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
596

597 598 599 600 601
  if (child == NULL)
    g_warning ("The file did not contain the required tag \"%s\"\n"
               "Under the \"%s\" node.", name, glade_xml_node_get_name (node));

  return child;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
602 603 604
}

/* --------------------------- Parse Context ----------------------------*/
605 606

static GladeXmlContext *
607
glade_xml_context_new_real (GladeXmlDoc *doc, gboolean freedoc, xmlNsPtr ns)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
608
{
609 610 611 612 613
  GladeXmlContext *context = g_new0 (GladeXmlContext, 1);

  context->doc = doc;
  context->freedoc = freedoc;
  context->ns = ns;
614

615
  return context;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
616 617
}

618
GladeXmlContext *
619
glade_xml_context_new (GladeXmlDoc *doc, const gchar *name_space)
620
{
621 622
  /* We are not using the namespace now */
  return glade_xml_context_new_real (doc, TRUE, NULL);
623 624
}

Jose Maria Celorio's avatar
Jose Maria Celorio committed
625
void
626
glade_xml_context_destroy (GladeXmlContext * context)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
627
{
628 629 630 631
  g_return_if_fail (context != NULL);
  if (context->freedoc)
    xmlFreeDoc ((xmlDoc *) context->doc);
  g_free (context);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
632 633
}

Chema Celorio's avatar
Chema Celorio committed
634
GladeXmlContext *
635 636 637
glade_xml_context_new_from_path (const gchar *full_path,
                                 const gchar *nspace,
                                 const gchar *root_name)
638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
{
  GladeXmlContext *context;
  xmlDocPtr doc;
  xmlNsPtr name_space;
  xmlNodePtr root;

  g_return_val_if_fail (full_path != NULL, NULL);

  doc = xmlParseFile (full_path);

  /* That's not an error condition.  The file is not readable, and we can't know it
   * before we try to read it (testing for readability is a call to race conditions).
   * So we should not print a warning */
  if (doc == NULL)
    return NULL;

  if (doc->children == NULL)
    {
      g_warning ("Invalid xml File, tree empty [%s]&", full_path);
      xmlFreeDoc (doc);
      return NULL;
    }

  name_space = xmlSearchNsByHref (doc, doc->children, BAD_CAST (nspace));
  if (name_space == NULL && nspace != NULL)
    {
      g_warning ("The file did not contain the expected name space\n"
                 "Expected \"%s\" [%s]", nspace, full_path);
      xmlFreeDoc (doc);
      return NULL;
    }

  root = xmlDocGetRootElement (doc);
  if (root_name != NULL &&
      ((root->name == NULL) ||
       (xmlStrcmp (root->name, BAD_CAST (root_name)) != 0)))
    {
      g_warning ("The file did not contain the expected root name\n"
                 "Expected \"%s\", actual : \"%s\" [%s]",
                 root_name, root->name, full_path);
      xmlFreeDoc (doc);
      return NULL;
    }

  context = glade_xml_context_new_real ((GladeXmlDoc *) doc, TRUE, name_space);

  return context;
Jose Maria Celorio's avatar
Jose Maria Celorio committed
685 686
}

Chema Celorio's avatar
Chema Celorio committed
687 688 689 690 691 692 693
/**
 * glade_xml_context_free:
 * @context: 
 * 
 * Similar to glade_xml_context_destroy but it also frees the document set in the context
 **/
void
694
glade_xml_context_free (GladeXmlContext *context)
Jose Maria Celorio's avatar
Jose Maria Celorio committed
695
{
696 697 698 699 700 701
  g_return_if_fail (context != NULL);
  if (context->doc)
    xmlFreeDoc ((xmlDocPtr) context->doc);
  context->doc = NULL;

  g_free (context);
Chema Celorio's avatar
Chema Celorio committed
702
}
Jose Maria Celorio's avatar
Jose Maria Celorio committed
703

Chema Celorio's avatar
Chema Celorio committed
704
void
705 706
glade_xml_node_append_child (GladeXmlNode *node_in,
                             GladeXmlNode *child_in)
Chema Celorio's avatar
Chema Celorio committed
707
{
708 709 710 711 712 713 714
  xmlNodePtr node = (xmlNodePtr) node_in;
  xmlNodePtr child = (xmlNodePtr) child_in;

  g_return_if_fail (node != NULL);
  g_return_if_fail (child != NULL);

  xmlAddChild (node, child);
Chema Celorio's avatar
Chema Celorio committed
715 716
}

717
void
718
glade_xml_node_remove (GladeXmlNode * node_in)
719
{
720 721 722 723 724
  xmlNodePtr node = (xmlNodePtr) node_in;

  g_return_if_fail (node != NULL);

  xmlReplaceNode (node, NULL);
725 726 727
}


Chema Celorio's avatar
Chema Celorio committed
728
GladeXmlNode *
729
glade_xml_node_new (GladeXmlContext *context, const gchar *name)
Chema Celorio's avatar
Chema Celorio committed
730
{
731 732
  g_return_val_if_fail (context != NULL, NULL);
  g_return_val_if_fail (name != NULL, NULL);
Chema Celorio's avatar
Chema Celorio committed
733

734 735
  return (GladeXmlNode *) xmlNewDocNode ((xmlDocPtr) context->doc, context->ns,
                                         BAD_CAST (name), NULL);
Jose Maria Celorio's avatar
Jose Maria Celorio committed
736
}
737

738
GladeXmlNode *
739
glade_xml_node_new_comment (GladeXmlContext *context, const gchar *comment)
740
{
741 742
  g_return_val_if_fail (context != NULL, NULL);
  g_return_val_if_fail (comment != NULL, NULL);
743

744 745
  return (GladeXmlNode *) xmlNewDocComment ((xmlDocPtr) context->doc,
                                            BAD_CAST (comment));
746 747
}

748 749 750 751 752 753 754 755 756 757 758
GladeXmlNode *
glade_xml_node_copy (GladeXmlNode *node)
{
  if (node)
    {
      xmlNodePtr xnode = (xmlNodePtr) node;
      return (GladeXmlNode *) xmlDocCopyNode (xnode, NULL, 1);
    }
  else
    return NULL;
}
759

760
void
761
glade_xml_node_delete (GladeXmlNode *node)
762
{
763
  xmlFreeNode ((xmlNodePtr) node);
764 765
}

766
GladeXmlDoc *
767
glade_xml_context_get_doc (GladeXmlContext *context)
Chema Celorio's avatar
Chema Celorio committed
768
{
769
  return context->doc;
770
}
Chema Celorio's avatar
Chema Celorio committed
771

772
gchar *
773
glade_xml_dump_from_context (GladeXmlContext *context)
774
{
775 776 777 778
  GladeXmlDoc *doc;
  xmlChar *string = NULL;
  gchar *text;
  int size;
779

780 781
  doc = glade_xml_context_get_doc (context);
  xmlDocDumpFormatMemory (&(doc->doc), &string, &size, 1);
782

783
  text = claim_string (string);
784

785
  return text;
786 787
}

788
gboolean
789
glade_xml_node_is_comment (GladeXmlNode *node_in)
790
{
791
  xmlNodePtr node = (xmlNodePtr) node_in;
792 793 794 795 796 797 798 799
  return (node) ? node->type == XML_COMMENT_NODE : FALSE;
}

static inline gboolean
glade_xml_node_is_comment_or_text (GladeXmlNode *node_in)
{
  xmlNodePtr node = (xmlNodePtr) node_in;
  return (node) ? node->type == XML_COMMENT_NODE || node->type == XML_TEXT_NODE : FALSE;
Chema Celorio's avatar
Chema Celorio committed
800 801 802
}

GladeXmlNode *
803
glade_xml_node_get_children (GladeXmlNode * node_in)
Chema Celorio's avatar
Chema Celorio committed
804
{
805 806
  xmlNodePtr node = (xmlNodePtr) node_in;
  xmlNodePtr children;
Chema Celorio's avatar
Chema Celorio committed
807

808
  children = node->children;
809
  while (glade_xml_node_is_comment_or_text ((GladeXmlNode *) children))
810
    children = children->next;
811

812
  return (GladeXmlNode *) children;
Chema Celorio's avatar
Chema Celorio committed
813 814
}

815
GladeXmlNode *
816
glade_xml_node_get_parent (GladeXmlNode *node_in)
817
{
818
  xmlNodePtr node = (xmlNodePtr) node_in;
819

820
  return (GladeXmlNode *) node->parent;
821 822 823
}


824
GladeXmlNode *
825
glade_xml_node_get_children_with_comments (GladeXmlNode *node_in)
826
{
827
  xmlNodePtr node = (xmlNodePtr) node_in;
828

829
  return (GladeXmlNode *) node->children;
830 831
}

Chema Celorio's avatar
Chema Celorio committed
832
GladeXmlNode *
833
glade_xml_node_next (GladeXmlNode *node_in)
Chema Celorio's avatar
Chema Celorio committed
834
{
835
  xmlNodePtr node = (xmlNodePtr) node_in;
836

837
  node = node->next;
838
  while (glade_xml_node_is_comment_or_text ((GladeXmlNode *) node))
839
    node = node->next;
840

841
  return (GladeXmlNode *) node;
Chema Celorio's avatar
Chema Celorio committed
842 843
}

844
GladeXmlNode *
845
glade_xml_node_next_with_comments (GladeXmlNode *node_in)
846
{
847
  xmlNodePtr node = (xmlNodePtr) node_in;
848

849
  return (GladeXmlNode *) node->next;
850 851
}

852
GladeXmlNode *
853
glade_xml_node_prev_with_comments (GladeXmlNode *node_in)
854 855 856 857 858
{
  xmlNodePtr node = (xmlNodePtr) node_in;

  return (GladeXmlNode *) node->prev;
}
859

Chema Celorio's avatar
Chema Celorio committed
860
const gchar *
861
glade_xml_node_get_name (GladeXmlNode *node_in)
Chema Celorio's avatar
Chema Celorio committed
862
{
863
  xmlNodePtr node = (xmlNodePtr) node_in;
Chema Celorio's avatar
Chema Celorio committed
864

865
  return CAST_BAD (node->name);
Chema Celorio's avatar
Chema Celorio committed
866 867 868 869 870
}

GladeXmlDoc *
glade_xml_doc_new (void)
{
871
  xmlDocPtr xml_doc = xmlNewDoc (BAD_CAST ("1.0"));
Chema Celorio's avatar
Chema Celorio committed
872

873
  return (GladeXmlDoc *) xml_doc;
Chema Celorio's avatar
Chema Celorio committed
874
}
875

Chema Celorio's avatar
Chema Celorio committed
876
void
877
glade_xml_doc_set_root (GladeXmlDoc *doc_in, GladeXmlNode *node_in)
Chema Celorio's avatar
Chema Celorio committed
878
{
879 880
  xmlNodePtr node = (xmlNodePtr) node_in;
  xmlDocPtr doc = (xmlDocPtr) doc_in;
Chema Celorio's avatar
Chema Celorio committed
881

882
  xmlDocSetRootElement (doc, node);
Chema Celorio's avatar
Chema Celorio committed
883 884 885
}

gint
886
glade_xml_doc_save (GladeXmlDoc *doc_in, const gchar *full_path)
Chema Celorio's avatar
Chema Celorio committed
887
{
888
  xmlDocPtr doc = (xmlDocPtr) doc_in;
Chema Celorio's avatar
Chema Celorio committed
889

890 891
  xmlKeepBlanksDefault (0);
  return xmlSaveFormatFileEnc (full_path, doc, "UTF-8", 1);
Chema Celorio's avatar
Chema Celorio committed
892 893 894
}

void
895
glade_xml_doc_free (GladeXmlDoc *doc_in)
Chema Celorio's avatar
Chema Celorio committed
896
{
897 898 899
  xmlDocPtr doc = (xmlDocPtr) doc_in;

  xmlFreeDoc (doc);
Chema Celorio's avatar
Chema Celorio committed
900 901
}

902 903 904 905 906 907
/**
 * glade_xml_doc_get_root:
 * @doc: a #GladeXmlDoc
 *
 * Returns: the #GladeXmlNode that is the document root of @doc
 */
Chema Celorio's avatar
Chema Celorio committed
908
GladeXmlNode *
909
glade_xml_doc_get_root (GladeXmlDoc *doc)
Chema Celorio's avatar
Chema Celorio committed
910
{
911
  xmlNodePtr node;
Chema Celorio's avatar
Chema Celorio committed
912

913
  node = xmlDocGetRootElement ((xmlDocPtr) (doc));
Chema Celorio's avatar
Chema Celorio committed
914

915
  return (GladeXmlNode *) node;
Chema Celorio's avatar
Chema Celorio committed
916
}
917

Juan Pablo Ugarte's avatar
Juan Pablo Ugarte committed
918
gboolean
919 920 921 922
glade_xml_load_sym_from_node (GladeXmlNode *node_in,
                              GModule      *module,
                              gchar        *tagname,
                              gpointer     *sym_location)
923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962
{
  static GModule *self = NULL;
  gboolean retval = FALSE;
  gchar *buff;

  if (!self)
    self = g_module_open (NULL, 0);

  if ((buff = glade_xml_get_value_string (node_in, tagname)) != NULL)
    {
      if (!module)
        {
          g_warning ("Catalog specified symbol '%s' for tag '%s', "
                     "no module available to load it from !", buff, tagname);
          g_free (buff);
          return FALSE;
        }

      /* I use here a g_warning to signal these errors instead of a dialog 
       * box, as if there is one of this kind of errors, there will probably 
       * a lot of them, and we don't want to inflict the user the pain of 
       * plenty of dialog boxes.  Ideally, we should collect these errors, 
       * and show all of them at the end of the load process.
       *
       * I dont know who wrote the above in glade-property-class.c, but
       * its a good point... makeing a bugzilla entry.
       *  -Tristan
       *
       * XXX http://bugzilla.gnome.org/show_bug.cgi?id=331797
       */
      if (g_module_symbol (module, buff, sym_location) ||
          g_module_symbol (self, buff, sym_location))
        retval = TRUE;
      else
        g_warning ("Could not find %s in %s or in global namespace\n",
                   buff, g_module_name (module));

      g_free (buff);
    }
  return retval;
Tristan Van Berkom's avatar
Tristan Van Berkom committed
963
}
964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981

GladeXmlNode *
glade_xml_doc_new_comment (GladeXmlDoc *doc, const gchar *comment)
{
  return (GladeXmlNode *) xmlNewDocComment ((xmlDocPtr) (doc), BAD_CAST (comment));
}

GladeXmlNode *
glade_xml_node_add_prev_sibling (GladeXmlNode *node, GladeXmlNode *new_node)
{
  return (GladeXmlNode *) xmlAddPrevSibling ((xmlNodePtr) node, (xmlNodePtr) new_node);
}

GladeXmlNode *
glade_xml_node_add_next_sibling (GladeXmlNode *node, GladeXmlNode *new_node)
{
  return (GladeXmlNode *) xmlAddNextSibling ((xmlNodePtr) node, (xmlNodePtr) new_node);
}
982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002


/* Private API */
#include "glade-private.h"

void
_glade_xml_error_reset_last (void)
{
  xmlResetLastError ();
}

gchar *
_glade_xml_error_get_last_message ()
{
  xmlErrorPtr error = xmlGetLastError ();

  if (error)
    return g_strdup_printf ("Error parsing file '%s' on line %d \n%s",
                            error->file, error->line, error->message);
  return NULL;
}