]> git.sur5r.net Git - glabels/blobdiff - glabels2/src/xml-label.c
2009-09-17 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / src / xml-label.c
index c18f3e725a01fdd971ea46316039233b3bb673c4..d1d53423d4dfd1850eba97375d4b7acf15a1b352 100644 (file)
@@ -1,32 +1,35 @@
 /*
- *  (GLABELS) Label and Business Card Creation program for GNOME
+ *  xml-label.c
+ *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
  *
- *  label.c:  GLabels xml label module
+ *  This file is part of gLabels.
  *
- *  Copyright (C) 2001-2002  Jim Evins <evins@snaught.com>.
- *
- *  This program is free software; you can redistribute it and/or modify
+ *  gLabels 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
+ *  the Free Software Foundation, either version 3 of the License, or
  *  (at your option) any later version.
  *
- *  This program is distributed in the hope that it will be useful,
+ *  gLabels 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 
-#include <gnome.h>
+#include "xml-label.h"
 
+#include <glib/gi18n.h>
+#include <glib.h>
 #include <libxml/tree.h>
 #include <libxml/parser.h>
+#include <libxml/xinclude.h>
+#include <gdk-pixbuf/gdk-pixdata.h>
 
+#include <libglabels/libglabels.h>
 #include "label.h"
 #include "label-object.h"
 #include "label-text.h"
 #include "label-ellipse.h"
 #include "label-image.h"
 #include "label-barcode.h"
-#include "template.h"
-#include "xml-label.h"
 #include "xml-label-04.h"
 #include "util.h"
 
 #include "debug.h"
 
+
 /*========================================================*/
 /* Private macros and constants.                          */
 /*========================================================*/
-#define NAME_SPACE "http://snaught.com/glabels/1.92/"
 #define COMPAT01_NAME_SPACE "http://snaught.com/glabels/0.1/"
 #define COMPAT04_NAME_SPACE "http://snaught.com/glabels/0.4/"
+#define COMPAT20_NAME_SPACE "http://snaught.com/glabels/2.0/"
+
 
 /*========================================================*/
 /* Private types.                                         */
 /*========================================================*/
 
+
 /*========================================================*/
 /* Private globals.                                       */
 /*========================================================*/
 
+
 /*========================================================*/
 /* Private function prototypes.                           */
 /*========================================================*/
 
-static glLabel *xml_doc_to_label (xmlDocPtr doc, glXMLLabelStatus *status);
-static glLabel *xml_parse_label (xmlNodePtr root, glXMLLabelStatus *status);
-static void xml_parse_objects (xmlNodePtr node, glLabel * label);
-static void xml_parse_object(xmlNodePtr node, glLabel *label);
-static glLabelObject *xml_parse_text_props (xmlNodePtr node, glLabel *label);
-static glLabelObject *xml_parse_box_props (xmlNodePtr node, glLabel *label);
-static glLabelObject *xml_parse_line_props (xmlNodePtr node, glLabel *label);
-static glLabelObject *xml_parse_ellipse_props (xmlNodePtr node, glLabel *label);
-static glLabelObject *xml_parse_image_props (xmlNodePtr node, glLabel *label);
-static glLabelObject *xml_parse_barcode_props (xmlNodePtr node, glLabel *label);
-static void xml_parse_merge_fields (xmlNodePtr node, glLabel *label);
-
-static xmlDocPtr xml_label_to_doc (glLabel * label, glXMLLabelStatus *status);
-static void xml_create_objects (xmlNodePtr root, xmlNsPtr ns, glLabel * label);
-static void xml_create_object (xmlNodePtr root, xmlNsPtr ns,
-                              glLabelObject * object);
-static void xml_create_text_props (xmlNodePtr root, xmlNsPtr ns,
-                                glLabelObject * object);
-static void xml_create_box_props (xmlNodePtr root, xmlNsPtr ns,
-                               glLabelObject * object);
-static void xml_create_line_props (xmlNodePtr root, xmlNsPtr ns,
-                                glLabelObject * object);
-static void xml_create_ellipse_props (xmlNodePtr root, xmlNsPtr ns,
-                                   glLabelObject * object);
-static void xml_create_image_props (xmlNodePtr root, xmlNsPtr ns,
-                                 glLabelObject * object);
-static void xml_create_barcode_props (xmlNodePtr root, xmlNsPtr ns,
-                                   glLabelObject * object);
-static void xml_create_merge_fields (xmlNodePtr root, xmlNsPtr ns,
-                                     glLabel * label);
+static glLabel       *xml_doc_to_label         (xmlDocPtr         doc,
+                                               glXMLLabelStatus *status);
+
+static glLabel       *xml_parse_label          (xmlNodePtr        root,
+                                               glXMLLabelStatus *status);
+
+static void           xml_parse_objects        (xmlNodePtr        node,
+                                               glLabel          *label);
+
+static void           xml_parse_object_text    (xmlNodePtr        node,
+                                               glLabel          *label);
+
+static void           xml_parse_object_box     (xmlNodePtr        node,
+                                               glLabel          *label);
+
+static void           xml_parse_object_ellipse (xmlNodePtr        node,
+                                               glLabel          *label);
+
+static void           xml_parse_object_line    (xmlNodePtr        node,
+                                               glLabel          *label);
+
+static void           xml_parse_object_image   (xmlNodePtr        node,
+                                               glLabel          *label);
+
+static void           xml_parse_object_barcode (xmlNodePtr        node,
+                                               glLabel          *label);
+
+static void           xml_parse_merge_fields   (xmlNodePtr        node,
+                                               glLabel          *label);
+
+static void           xml_parse_data           (xmlNodePtr        node,
+                                               glLabel          *label);
+
+static void           xml_parse_pixdata        (xmlNodePtr        node,
+                                               glLabel          *label);
+
+static void           xml_parse_toplevel_span  (xmlNodePtr        node,
+                                               glLabelObject    *object);
+
+static void           xml_parse_affine_attrs   (xmlNodePtr        node,
+                                               glLabelObject    *object);
+
+static void           xml_parse_shadow_attrs   (xmlNodePtr        node,
+                                               glLabelObject    *object);
+
+static xmlDocPtr      xml_label_to_doc         (glLabel          *label,
+                                               glXMLLabelStatus *status);
+
+static void           xml_create_objects       (xmlNodePtr        root,
+                                               xmlNsPtr          ns,
+                                               glLabel          *label);
+
+static void           xml_create_object_text   (xmlNodePtr        root,
+                                               xmlNsPtr          ns,
+                                               glLabelObject    *object);
+
+static void           xml_create_object_box    (xmlNodePtr        root,
+                                               xmlNsPtr          ns,
+                                               glLabelObject    *object);
+
+static void           xml_create_object_line   (xmlNodePtr        root,
+                                               xmlNsPtr          ns,
+                                               glLabelObject    *object);
+
+static void           xml_create_object_ellipse(xmlNodePtr        root,
+                                               xmlNsPtr          ns,
+                                               glLabelObject    *object);
+
+static void           xml_create_object_image  (xmlNodePtr        root,
+                                               xmlNsPtr          ns,
+                                               glLabelObject    *object);
+
+static void           xml_create_object_barcode(xmlNodePtr        root,
+                                               xmlNsPtr          ns,
+                                               glLabelObject    *object);
+
+static void           xml_create_merge_fields  (xmlNodePtr        root,
+                                               xmlNsPtr          ns,
+                                               glLabel          *label);
+
+static void           xml_create_data          (xmlNodePtr        root,
+                                               xmlNsPtr          ns,
+                                               glLabel          *label);
+
+static void           xml_create_pixdata       (xmlNodePtr        root,
+                                               xmlNsPtr          ns,
+                                               glLabel          *label,
+                                               gchar            *name);
+
+static void           xml_create_toplevel_span (xmlNodePtr        node,
+                                               xmlNsPtr          ns,
+                                               glLabelText      *object_text);
+
+static void           xml_create_affine_attrs  (xmlNodePtr        node,
+                                               glLabelObject    *object);
+
+static void           xml_create_shadow_attrs  (xmlNodePtr        node,
+                                               glLabelObject    *object);
+
 
 /****************************************************************************/
 /* Open and read label from xml file.                                       */
 /****************************************************************************/
 glLabel *
-gl_xml_label_open (const gchar filename,
+gl_xml_label_open (const gchar      *utf8_filename,
                   glXMLLabelStatus *status)
 {
-       xmlDocPtr doc;
-       glLabel *label;
+       xmlDocPtr  doc;
+       glLabel   *label;
+       gchar     *filename;
 
        gl_debug (DEBUG_XML, "START");
 
-       doc = xmlParseFile (filename);
+       filename = g_filename_from_utf8 (utf8_filename, -1, NULL, NULL, NULL);
+       g_return_val_if_fail (filename, NULL);
+
+        doc = xmlReadFile (filename, NULL, XML_PARSE_HUGE);
        if (!doc) {
-               g_warning (_("xmlParseFile error"));
+               g_message (_("xmlParseFile error"));
                *status = XML_LABEL_ERROR_OPEN_PARSE;
                return NULL;
        }
 
+       xmlXIncludeProcess (doc);
+       xmlReconciliateNs (doc, xmlDocGetRootElement (doc));
+
        label = xml_doc_to_label (doc, status);
 
        xmlFreeDoc (doc);
 
-       gl_label_set_filename (label, filename);
-       gl_label_clear_modified (label);
+       if (label) {
+               gl_label_set_filename (label, utf8_filename);
+               gl_label_clear_modified (label);
+       }
 
+       g_free (filename);
        gl_debug (DEBUG_XML, "END");
 
        return label;
 }
 
+
 /****************************************************************************/
 /* Read label from xml buffer.                                              */
 /****************************************************************************/
 glLabel *
-gl_xml_label_open_buffer (const gchar buffer,
+gl_xml_label_open_buffer (const gchar      *buffer,
                          glXMLLabelStatus *status)
 {
-       xmlDocPtr doc;
-       glLabel *label;
+       xmlDocPtr  doc;
+       glLabel   *label;
 
        gl_debug (DEBUG_XML, "START");
 
-       doc = xmlParseDoc ((xmlChar *) buffer);
+        doc = xmlReadDoc ((xmlChar *) buffer, NULL, NULL, XML_PARSE_HUGE);
        if (!doc) {
-               g_warning (_("xmlParseFile error"));
+               g_message (_("xmlParseFile error"));
                *status = XML_LABEL_ERROR_OPEN_PARSE;
                return NULL;
        }
 
        label = xml_doc_to_label (doc, status);
 
-       gl_label_clear_modified (label);
-
        xmlFreeDoc (doc);
 
+       if (label) {
+               gl_label_clear_modified (label);
+       }
+
        gl_debug (DEBUG_XML, "END");
 
        return label;
 }
 
+
 /*--------------------------------------------------------------------------*/
 /* PRIVATE.  Parse xml doc structure and create label.                      */
 /*--------------------------------------------------------------------------*/
 static glLabel *
-xml_doc_to_label (xmlDocPtr doc,
+xml_doc_to_label (xmlDocPtr         doc,
                  glXMLLabelStatus *status)
 {
-       xmlNodePtr root, node;
-       xmlNsPtr ns;
-       glLabel *label;
+       xmlNodePtr  root;
+       glLabel    *label;
 
        gl_debug (DEBUG_XML, "START");
 
@@ -172,81 +259,106 @@ xml_doc_to_label (xmlDocPtr doc,
 
        root = xmlDocGetRootElement (doc);
        if (!root || !root->name) {
-               g_warning (_("No document root"));
+               g_message (_("No document root"));
                *status = XML_LABEL_ERROR_OPEN_PARSE;
                return NULL;
        }
 
-       ns = xmlSearchNsByHref (doc, root, NAME_SPACE);
-       if (ns != NULL) {
-               label = xml_parse_label (root, status);
-       } else {
-               /* Try compatability mode 0.1 */
-               ns = xmlSearchNsByHref (doc, root, COMPAT01_NAME_SPACE);
-               if (ns != NULL) {
-                       g_warning (_("Importing from glabels 0.1 format"));
-                       g_warning ("TODO");
-                       label = NULL; /* TODO */
-               } else {
-                       /* Try compatability mode 0.4 */
-                       ns = xmlSearchNsByHref (doc, root,
-                                               COMPAT04_NAME_SPACE);
-                       if (ns != NULL) {
-                               g_warning (_("Importing from glabels 0.4 format"));
-                               label = gl_xml_label_04_parse (root, status);
-                       } else {
-                               g_warning (_("bad document, unknown glabels Namespace"));
-                               *status = XML_LABEL_ERROR_OPEN_PARSE;
-                               return NULL;
-                       }
-               }
-       }
+        /* Try compatability mode 0.1 */
+        if (xmlSearchNsByHref (doc, root, (xmlChar *)COMPAT01_NAME_SPACE))
+       {
+                g_message (_("Importing from glabels 0.1 format"));
+                g_message ("TODO");
+                label = NULL; /* TODO */
+                return label;
+        }
+
+        /* Try compatability mode 0.4 */
+        if (xmlSearchNsByHref (doc, root, (xmlChar *)COMPAT04_NAME_SPACE))
+       {
+                g_message (_("Importing from glabels 0.4 format"));
+                label = gl_xml_label_04_parse (root, status);
+                return label;
+        }
+
+        /* Test for current namespaces. */
+        if ( !xmlSearchNsByHref (doc, root, (xmlChar *)COMPAT20_NAME_SPACE) &&
+             !xmlSearchNsByHref (doc, root, (xmlChar *)LGL_XML_NAME_SPACE) )
+        {
+                g_message (_("Unknown glabels Namespace -- Using %s"),
+                           LGL_XML_NAME_SPACE);
+        }
+
+        label = xml_parse_label (root, status);
+        if (label)
+        {
+                gl_label_set_compression (label, xmlGetDocCompressMode (doc));
+        }
 
        gl_debug (DEBUG_XML, "END");
 
        return label;
 }
 
+
 /*--------------------------------------------------------------------------*/
 /* PRIVATE.  Parse xml root node and create label.                          */
 /*--------------------------------------------------------------------------*/
 static glLabel *
-xml_parse_label (xmlNodePtr       root,
+xml_parse_label (xmlNodePtr        root,
                 glXMLLabelStatus *status)
 {
-       xmlNodePtr node;
-       glLabel *label;
-       glTemplate *template;
+       xmlNodePtr   child_node;
+       glLabel     *label;
+       lglTemplate *template;
 
        gl_debug (DEBUG_XML, "START");
 
        *status = XML_LABEL_OK;
 
-       if (g_strcasecmp (root->name, "Document") != 0) {
-               g_warning (_("Bad root node = \"%s\""), root->name);
+       if (!lgl_xml_is_node (root, "Glabels-document")) {
+               g_message (_("Bad root node = \"%s\""), root->name);
                *status = XML_LABEL_ERROR_OPEN_PARSE;
                return NULL;
        }
 
        label = GL_LABEL(gl_label_new ());
 
-       for (node = root->xmlChildrenNode; node != NULL; node = node->next) {
+       /* Pass 1, extract data nodes to pre-load cache. */
+       for (child_node = root->xmlChildrenNode; child_node != NULL; child_node = child_node->next) {
+               if (lgl_xml_is_node (child_node, "Data")) {
+                       xml_parse_data (child_node, label);
+               }
+       }
+
+       /* Pass 2, now extract everything else. */
+       for (child_node = root->xmlChildrenNode;
+             child_node != NULL;
+            child_node = child_node->next) {
 
-               if (g_strcasecmp (node->name, "Sheet") == 0) {
-                       template = gl_template_xml_parse_sheet (node);
+               if (lgl_xml_is_node (child_node, "Template")) {
+                       template = lgl_xml_template_parse_template_node (child_node);
                        if (!template) {
+                               g_object_unref (label);
                                *status = XML_LABEL_UNKNOWN_MEDIA;
                                return NULL;
                        }
+                       lgl_db_register_template (template);
                        gl_label_set_template (label, template);
-                       gl_template_free (&template);
-               } else if (g_strcasecmp (node->name, "Objects") == 0) {
-                       xml_parse_objects (node, label);
-               } else if (g_strcasecmp (node->name, "Merge_Fields") == 0) {
-                       xml_parse_merge_fields (node, label);
+                       lgl_template_free (template);
+               } else if (lgl_xml_is_node (child_node, "Objects")) {
+                       xml_parse_objects (child_node, label);
+               } else if (lgl_xml_is_node (child_node, "Merge")) {
+                       xml_parse_merge_fields (child_node, label);
+               } else if (lgl_xml_is_node (child_node, "Data")) {
+                       /* Handled in pass 1. */
                } else {
-                       if (!xmlNodeIsText (node)) {
-                               g_warning (_("bad node =  \"%s\""), node->name);
+                       if (!xmlNodeIsText (child_node)) {
+                               g_message (_("bad node in Document node =  \"%s\""),
+                                          child_node->name);
+                               g_object_unref (label);
+                               *status = XML_LABEL_ERROR_OPEN_PARSE;
+                               return NULL;
                        }
                }
        }
@@ -256,29 +368,40 @@ xml_parse_label (xmlNodePtr       root,
        return label;
 }
 
+
 /*--------------------------------------------------------------------------*/
 /* PRIVATE.  Parse Objects node.                                            */
 /*--------------------------------------------------------------------------*/
 static void
-xml_parse_objects (xmlNodePtr objects_node,
-                  glLabel label)
+xml_parse_objects (xmlNodePtr  node,
+                  glLabel    *label)
 {
-       gboolean rotate_flag;
-       xmlNodePtr node;
+       gboolean    rotate_flag;
+       xmlNodePtr  child;
 
        gl_debug (DEBUG_XML, "START");
 
-       rotate_flag =
-               !(g_strcasecmp (xmlGetProp (objects_node, "rotate"), "false") == 0);
+       rotate_flag = lgl_xml_get_prop_boolean (node, "rotate", FALSE);
        gl_label_set_rotate_flag (label, rotate_flag);
 
-       for (node = objects_node->xmlChildrenNode; node != NULL; node = node->next) {
-
-               if (g_strcasecmp (node->name, "Object") == 0) {
-                       xml_parse_object (node, label);
+       for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
+
+               if (lgl_xml_is_node (child, "Object-text")) {
+                       xml_parse_object_text (child, label);
+               } else if (lgl_xml_is_node (child, "Object-box")) {
+                       xml_parse_object_box (child, label);
+               } else if (lgl_xml_is_node (child, "Object-ellipse")) {
+                       xml_parse_object_ellipse (child, label);
+               } else if (lgl_xml_is_node (child, "Object-line")) {
+                       xml_parse_object_line (child, label);
+               } else if (lgl_xml_is_node (child, "Object-image")) {
+                       xml_parse_object_image (child, label);
+               } else if (lgl_xml_is_node (child, "Object-barcode")) {
+                       xml_parse_object_barcode (child, label);
                } else {
-                       if (!xmlNodeIsText (node)) {
-                               g_warning (_("bad node =  \"%s\""), node->name);
+                       if (!xmlNodeIsText (child)) {
+                               g_message (_("bad node =  \"%s\""), child->name);
+                               break;
                        }
                }
        }
@@ -286,350 +409,418 @@ xml_parse_objects (xmlNodePtr objects_node,
        gl_debug (DEBUG_XML, "END");
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Parse XML Object Node                                          */
+/* PRIVATE.  Parse XML Objects->Object-text Node                            */
 /*--------------------------------------------------------------------------*/
 static void
-xml_parse_object (xmlNodePtr object_node,
-                 glLabel * label)
+xml_parse_object_text (xmlNodePtr  node,
+                      glLabel    *label)
 {
-       glLabelObject *object;
-       gdouble        x, y;
-       gchar         *type_string;
-       gdouble        affine[6];
+       GObject          *object;
+       gdouble           x, y;
+       gdouble           w, h;
+       gchar            *string;
+       PangoAlignment    align;
+       gboolean          auto_shrink;
+       xmlNodePtr        child;
 
        gl_debug (DEBUG_XML, "START");
 
-       type_string = xmlGetProp (object_node, "type");
-
-       if ( g_strcasecmp (type_string, "text") == 0 ) {
-               object = xml_parse_text_props (object_node, label);
-       } else if ( g_strcasecmp (type_string, "box") == 0 ) {
-               object = xml_parse_box_props (object_node, label);
-       } else if ( g_strcasecmp (type_string, "line") == 0 ) {
-               object = xml_parse_line_props (object_node, label);
-       } else if ( g_strcasecmp (type_string, "ellipse") == 0 ) {
-               object = xml_parse_ellipse_props (object_node, label);
-       } else if ( g_strcasecmp (type_string, "image") == 0 ) {
-               object = xml_parse_image_props (object_node, label);
-       } else if ( g_strcasecmp (type_string, "barcode") == 0 ) {
-               object = xml_parse_barcode_props (object_node, label);
-       } else {
-               g_warning ("Unknown label object type \"%s\"", type_string);
-               return;
-       }
+       object = gl_label_text_new (label);
+
+       /* position attrs */
+       x = lgl_xml_get_prop_length (node, "x", 0.0);
+       y = lgl_xml_get_prop_length (node, "y", 0.0);
+       gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y);
+
+       /* implied size attrs */
+       w = lgl_xml_get_prop_length (node, "w", 0);
+       h = lgl_xml_get_prop_length (node, "h", 0);
+       gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h);
+
+       /* justify attr */
+       string = lgl_xml_get_prop_string (node, "justify", NULL);
+       align = gl_util_string_to_align (string);
+       g_free (string);
+       gl_label_object_set_text_alignment (GL_LABEL_OBJECT(object), align);
 
-       x = g_strtod (xmlGetProp (object_node, "x"), NULL);
-       y = g_strtod (xmlGetProp (object_node, "y"), NULL);
+       /* auto_shrink attr */
+       auto_shrink = lgl_xml_get_prop_boolean (node, "auto_shrink", FALSE);
+       gl_label_text_set_auto_shrink (GL_LABEL_TEXT(object), auto_shrink);
 
-       gl_label_object_set_position (object, x, y);
+       /* affine attrs */
+       xml_parse_affine_attrs (node, GL_LABEL_OBJECT(object));
 
-       affine[0] = g_strtod (xmlGetProp (object_node, "a0"), NULL);
-       affine[1] = g_strtod (xmlGetProp (object_node, "a1"), NULL);
-       affine[2] = g_strtod (xmlGetProp (object_node, "a2"), NULL);
-       affine[3] = g_strtod (xmlGetProp (object_node, "a3"), NULL);
-       affine[4] = g_strtod (xmlGetProp (object_node, "a4"), NULL);
-       affine[5] = g_strtod (xmlGetProp (object_node, "a5"), NULL);
+       /* shadow attrs */
+       xml_parse_shadow_attrs (node, GL_LABEL_OBJECT(object));
 
-       gl_label_object_set_affine (object, affine);
+       /* Process children */
+       for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
+               if (lgl_xml_is_node (child, "Span")) {
+                       xml_parse_toplevel_span (child, GL_LABEL_OBJECT(object));
+                       break;
+               } else {
+                       if (!xmlNodeIsText (child)) {
+                               g_message ("Unexpected Object-text child: \"%s\"",
+                                          child->name);
+                       }
+               }
+       }
 
        gl_debug (DEBUG_XML, "END");
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Parse XML Label->Text Node Properties                          */
+/* PRIVATE.  Parse XML Objects->Object-box Node                             */
 /*--------------------------------------------------------------------------*/
-static glLabelObject *
-xml_parse_text_props (xmlNodePtr object_node,
-                     glLabel label)
+static void
+xml_parse_object_box (xmlNodePtr  node,
+                     glLabel    *label)
 {
-       GObject *object;
-       GList *lines;
-       gchar *font_family;
-       gdouble font_size;
-       GnomeFontWeight font_weight;
-       gboolean font_italic_flag;
-       guint color;
-       GtkJustification just;
-       xmlNodePtr line_node, text_node;
-       glTextNode *node_text;
-       GList *nodes;
+       GObject      *object;
+       gdouble       x, y;
+       gdouble       w, h;
+       gdouble       line_width;
+       glColorNode  *line_color_node;
+       gchar        *string;
+       glColorNode  *fill_color_node;
 
        gl_debug (DEBUG_XML, "START");
 
-       object = gl_label_text_new (label);
-
-       font_family = xmlGetProp (object_node, "font_family");
-       font_size = g_strtod (xmlGetProp (object_node, "font_size"), NULL);
-       font_weight = gl_util_string_to_weight (xmlGetProp (object_node,
-                                                         "font_weight"));
-       font_italic_flag =
-               !(g_strcasecmp (xmlGetProp (object_node, "font_italic"), "false") ==
-                 0);
-
-       just = gl_util_string_to_just (xmlGetProp (object_node, "justify"));
+       object = gl_label_box_new (label);
 
-       sscanf (xmlGetProp (object_node, "color"), "%x", &color);
+       /* position attrs */
+       x = lgl_xml_get_prop_length (node, "x", 0.0);
+       y = lgl_xml_get_prop_length (node, "y", 0.0);
+       gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y);
 
-       lines = NULL;
-       for (line_node = object_node->xmlChildrenNode;
-            line_node != NULL;
-            line_node = line_node->next) {
-
-               if (g_strcasecmp (line_node->name, "Line") == 0) {
-
-                       nodes = NULL;
-                       for (text_node = line_node->xmlChildrenNode;
-                            text_node != NULL; text_node = text_node->next) {
-
-                               if (g_strcasecmp (text_node->name, "Field") == 0) {
-                                       node_text = g_new0 (glTextNode, 1);
-                                       node_text->field_flag = TRUE;
-                                       node_text->data =
-                                               xmlGetProp (text_node, "name");
-                                       nodes =
-                                               g_list_append (nodes, node_text);
-                               } else if (g_strcasecmp (text_node->name, "Literal") == 0) {
-                                       node_text = g_new0 (glTextNode, 1);
-                                       node_text->field_flag = FALSE;
-                                       node_text->data =
-                                               xmlNodeGetContent (text_node);
-                                       nodes =
-                                               g_list_append (nodes, node_text);
-                               } else if (!xmlNodeIsText) {
-                                       g_warning ("Unexpected Text Line child: \"%s\"",
-                                                  text_node->name);
-                               }
+       /* size attrs */
+       w = lgl_xml_get_prop_length (node, "w", 0);
+       h = lgl_xml_get_prop_length (node, "h", 0);
+       gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h);
 
-                       }
-                       lines = g_list_append (lines, nodes);
+       /* line attrs */
+       line_width = lgl_xml_get_prop_length (node, "line_width", 1.0);
+       gl_label_object_set_line_width (GL_LABEL_OBJECT(object), line_width);
+       
+       line_color_node = gl_color_node_new_default ();
+       string = lgl_xml_get_prop_string (node, "line_color_field", NULL);
+       if ( string ) {
+               line_color_node->field_flag = TRUE;
+               line_color_node->key = string;
+       } else {
+               line_color_node->color = lgl_xml_get_prop_uint (node, "line_color", 0);
+       }
+       gl_label_object_set_line_color (GL_LABEL_OBJECT(object), line_color_node);
+       gl_color_node_free (&line_color_node);
 
-               } else if (!xmlNodeIsText (line_node)) {
-                       g_warning ("Unexpected Text child: \"%s\"",
-                                  line_node->name);
-               }
 
+       /* fill attrs */
+       fill_color_node = gl_color_node_new_default ();
+       string = lgl_xml_get_prop_string (node, "fill_color_field", NULL);
+       if ( string ) {
+               fill_color_node->field_flag = TRUE;
+               fill_color_node->key = string;
+       } else {
+               fill_color_node->color = lgl_xml_get_prop_uint (node, "fill_color", 0);
        }
+       gl_label_object_set_fill_color (GL_LABEL_OBJECT(object), fill_color_node);
+       gl_color_node_free (&fill_color_node);
+       
+       /* affine attrs */
+       xml_parse_affine_attrs (node, GL_LABEL_OBJECT(object));
 
-       gl_label_text_set_lines (GL_LABEL_TEXT(object), lines);
-       gl_label_text_set_props (GL_LABEL_TEXT(object),
-                                font_family, font_size, font_weight,
-                                font_italic_flag,
-                                color, just);
-
-       gl_text_node_lines_free (&lines);
-       g_free (font_family);
+       /* shadow attrs */
+       xml_parse_shadow_attrs (node, GL_LABEL_OBJECT(object));
 
        gl_debug (DEBUG_XML, "END");
-
-       return GL_LABEL_OBJECT(object);
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Parse XML Label->Box Node Properties                           */
+/* PRIVATE.  Parse XML Objects->Object-ellipse Node                         */
 /*--------------------------------------------------------------------------*/
-static glLabelObject *
-xml_parse_box_props (xmlNodePtr node,
-                    glLabel * label)
+static void
+xml_parse_object_ellipse (xmlNodePtr  node,
+                         glLabel    *label)
 {
-       GObject *object;
-       gdouble line_width;
-       guint line_color, fill_color;
-       gdouble w, h;
+       GObject     *object;
+       gdouble      x, y;
+       gdouble      w, h;
+       gdouble      line_width;
+       glColorNode *line_color_node;
+       gchar       *string;
+       glColorNode *fill_color_node;
 
        gl_debug (DEBUG_XML, "START");
 
-       object = gl_label_box_new (label);
-
-       w = g_strtod (xmlGetProp (node, "w"), NULL);
-       h = g_strtod (xmlGetProp (node, "h"), NULL);
-
-       line_width = g_strtod (xmlGetProp (node, "line_width"), NULL);
+       object = gl_label_ellipse_new (label);
 
-       sscanf (xmlGetProp (node, "line_color"), "%x", &line_color);
-       sscanf (xmlGetProp (node, "fill_color"), "%x", &fill_color);
+       /* position attrs */
+       x = lgl_xml_get_prop_length (node, "x", 0.0);
+       y = lgl_xml_get_prop_length (node, "y", 0.0);
+       gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y);
 
+       /* size attrs */
+       w = lgl_xml_get_prop_length (node, "w", 0);
+       h = lgl_xml_get_prop_length (node, "h", 0);
        gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h);
-       gl_label_box_set_line_width (GL_LABEL_BOX(object), line_width);
-       gl_label_box_set_line_color (GL_LABEL_BOX(object), line_color);
-       gl_label_box_set_fill_color (GL_LABEL_BOX(object), fill_color);
-
-       gl_debug (DEBUG_XML, "END");
 
-       return GL_LABEL_OBJECT(object);
-}
+       /* line attrs */
+       line_width = lgl_xml_get_prop_length (node, "line_width", 1.0);
+       gl_label_object_set_line_width (GL_LABEL_OBJECT(object), line_width);
 
-/*--------------------------------------------------------------------------*/
-/* PRIVATE.  Parse XML Label->Line Node Properties                          */
-/*--------------------------------------------------------------------------*/
-static glLabelObject *
-xml_parse_line_props (xmlNodePtr node,
-                     glLabel * label)
-{
-       GObject *object;
-       gdouble line_width;
-       guint line_color;
-       gdouble w, h;
-
-       gl_debug (DEBUG_XML, "START");
-
-       object = gl_label_line_new (label);
+       line_color_node = gl_color_node_new_default ();
+       string = lgl_xml_get_prop_string (node, "line_color_field", NULL);
+       if ( string ) {
+               line_color_node->field_flag = TRUE;
+               line_color_node->key = string;
+       } else {
+               line_color_node->color = lgl_xml_get_prop_uint (node, "line_color", 0);         
+       }
+       gl_label_object_set_line_color (GL_LABEL_OBJECT(object), line_color_node);
+       gl_color_node_free (&line_color_node);
 
-       w = g_strtod (xmlGetProp (node, "dx"), NULL);
-       h = g_strtod (xmlGetProp (node, "dy"), NULL);
 
-       line_width = g_strtod (xmlGetProp (node, "line_width"), NULL);
+       /* fill attrs */
+       fill_color_node = gl_color_node_new_default ();
+       string = lgl_xml_get_prop_string (node, "fill_color_field", NULL);
+       if ( string ) {
+               fill_color_node->field_flag = TRUE;
+               fill_color_node->key = string;
+       } else {
+               fill_color_node->color = lgl_xml_get_prop_uint (node, "fill_color", 0);
+       }
+       gl_label_object_set_fill_color (GL_LABEL_OBJECT(object), fill_color_node);
+       gl_color_node_free (&fill_color_node);
 
-       sscanf (xmlGetProp (node, "line_color"), "%x", &line_color);
+       /* affine attrs */
+       xml_parse_affine_attrs (node, GL_LABEL_OBJECT(object));
 
-       gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h);
-       gl_label_line_set_line_width (GL_LABEL_LINE(object), line_width);
-       gl_label_line_set_line_color (GL_LABEL_LINE(object), line_color);
+       /* shadow attrs */
+       xml_parse_shadow_attrs (node, GL_LABEL_OBJECT(object));
 
        gl_debug (DEBUG_XML, "END");
-
-       return GL_LABEL_OBJECT(object);
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Parse XML Label->Ellipse Node Properties                       */
+/* PRIVATE.  Parse XML Objects->Object-line Node                            */
 /*--------------------------------------------------------------------------*/
-static glLabelObject *
-xml_parse_ellipse_props (xmlNodePtr node,
-                        glLabel * label)
+static void
+xml_parse_object_line (xmlNodePtr  node,
+                      glLabel    *label)
 {
-       GObject *object;
-       gdouble line_width;
-       guint line_color, fill_color;
-       gdouble w, h;
+       GObject     *object;
+       gdouble      x, y;
+       gdouble      dx, dy;
+       gdouble      line_width;
+       glColorNode *line_color_node;
+       gchar       *string;
 
        gl_debug (DEBUG_XML, "START");
 
-       object = gl_label_ellipse_new (label);
-
-       w = g_strtod (xmlGetProp (node, "w"), NULL);
-       h = g_strtod (xmlGetProp (node, "h"), NULL);
+       object = gl_label_line_new (label);
 
-       line_width = g_strtod (xmlGetProp (node, "line_width"), NULL);
+       /* position attrs */
+       x = lgl_xml_get_prop_length (node, "x", 0.0);
+       y = lgl_xml_get_prop_length (node, "y", 0.0);
+       gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y);
+
+       /* length attrs */
+       dx = lgl_xml_get_prop_length (node, "dx", 0);
+       dy = lgl_xml_get_prop_length (node, "dy", 0);
+       gl_label_object_set_size (GL_LABEL_OBJECT(object), dx, dy);
+
+       /* line attrs */
+       line_width = lgl_xml_get_prop_length (node, "line_width", 1.0);
+       gl_label_object_set_line_width (GL_LABEL_OBJECT(object), line_width);
+       
+       line_color_node = gl_color_node_new_default ();
+       string = lgl_xml_get_prop_string (node, "line_color_field", NULL);
+       if ( string ) {
+               line_color_node->field_flag = TRUE;
+               line_color_node->key = string;
+       } else {
+               line_color_node->color = lgl_xml_get_prop_uint (node, "line_color", 0);         
+       }
+       gl_label_object_set_line_color (GL_LABEL_OBJECT(object), line_color_node);
+       gl_color_node_free (&line_color_node);
 
-       sscanf (xmlGetProp (node, "line_color"), "%x", &line_color);
-       sscanf (xmlGetProp (node, "fill_color"), "%x", &fill_color);
+       /* affine attrs */
+       xml_parse_affine_attrs (node, GL_LABEL_OBJECT(object));
 
-       gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h);
-       gl_label_ellipse_set_line_width (GL_LABEL_ELLIPSE(object), line_width);
-       gl_label_ellipse_set_line_color (GL_LABEL_ELLIPSE(object), line_color);
-       gl_label_ellipse_set_fill_color (GL_LABEL_ELLIPSE(object), fill_color);
+       /* shadow attrs */
+       xml_parse_shadow_attrs (node, GL_LABEL_OBJECT(object));
 
        gl_debug (DEBUG_XML, "END");
-
-       return GL_LABEL_OBJECT(object);
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Parse XML Label->Image Node Properties                         */
+/* PRIVATE.  Parse XML Objects->Object-image Node                           */
 /*--------------------------------------------------------------------------*/
-static glLabelObject *
-xml_parse_image_props (xmlNodePtr node,
-                      glLabel *label)
+static void
+xml_parse_object_image (xmlNodePtr  node,
+                       glLabel    *label)
 {
        GObject      *object;
-       xmlNodePtr    child;
+       gdouble       x, y;
        gdouble       w, h;
+       gchar        *string;
        glTextNode   *filename;
 
        gl_debug (DEBUG_XML, "START");
 
        object = gl_label_image_new (label);
 
-       w = g_strtod (xmlGetProp (node, "w"), NULL);
-       h = g_strtod (xmlGetProp (node, "h"), NULL);
+       /* position attrs */
+       x = lgl_xml_get_prop_length (node, "x", 0.0);
+       y = lgl_xml_get_prop_length (node, "y", 0.0);
+       gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y);
 
-       child = node->xmlChildrenNode;
-       filename = g_new0 (glTextNode, 1);
-       if (g_strcasecmp (child->name, "Field") == 0) {
-               filename->field_flag = TRUE;
-               filename->data = xmlGetProp (child, "name");
-       } else if (xmlNodeIsText (child)) {
+       /* src or field attr */
+       string = lgl_xml_get_prop_string (node, "src", NULL);
+       if ( string ) {
+               filename = g_new0 (glTextNode, 1);
                filename->field_flag = FALSE;
-               filename->data = xmlNodeGetContent (child);
+               filename->data = g_strdup ((gchar *)string);
+               gl_label_image_set_filename (GL_LABEL_IMAGE(object), filename);
+               gl_text_node_free (&filename);
+               xmlFree (string);
        } else {
-               g_warning ("Unexpected Image child: \"%s\"", child->name);
+               string = lgl_xml_get_prop_string (node, "field", NULL);
+               if ( string ) {
+                       filename = g_new0 (glTextNode, 1);
+                       filename->field_flag = TRUE;
+                       filename->data = g_strdup ((gchar *)string);
+                       gl_label_image_set_filename (GL_LABEL_IMAGE(object), filename);
+                       gl_text_node_free (&filename);
+                       xmlFree (string);
+               } else {
+                       g_message ("Missing Object-image src or field attr");
+               }
        }
 
+       /* size attrs */
+       w = lgl_xml_get_prop_length (node, "w", 0);
+       h = lgl_xml_get_prop_length (node, "h", 0);
        gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h);
-       gl_label_image_set_filename (GL_LABEL_IMAGE(object), filename);
 
-       gl_text_node_free (&filename);
+       /* affine attrs */
+       xml_parse_affine_attrs (node, GL_LABEL_OBJECT(object));
 
-       gl_debug (DEBUG_XML, "END");
+       /* shadow attrs */
+       xml_parse_shadow_attrs (node, GL_LABEL_OBJECT(object));
 
-       return GL_LABEL_OBJECT(object);
+       gl_debug (DEBUG_XML, "END");
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Parse XML Label->Barcode Node Properties                       */
+/* PRIVATE.  Parse XML Objects->Object-barcode Node                         */
 /*--------------------------------------------------------------------------*/
-static glLabelObject *
-xml_parse_barcode_props (xmlNodePtr node,
-                        glLabel *label)
+static void
+xml_parse_object_barcode (xmlNodePtr  node,
+                         glLabel    *label)
 {
        GObject            *object;
-       xmlNodePtr          child;
+       gdouble             x, y;
+       gdouble             w, h;
+       gchar              *string;
        glTextNode         *text_node;
-       glBarcodeStyle      style;
+       gchar              *id;
        gboolean            text_flag;
-       guint               color;
-       gdouble             scale;
+       gboolean            checksum_flag;
+       glColorNode        *color_node;
+       guint               format_digits;
 
        gl_debug (DEBUG_XML, "START");
 
        object = gl_label_barcode_new (label);
 
-       sscanf (xmlGetProp (node, "color"), "%x", &color);
+       /* position attrs */
+       x = lgl_xml_get_prop_length (node, "x", 0.0);
+       y = lgl_xml_get_prop_length (node, "y", 0.0);
+       gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y);
 
-       style = gl_barcode_text_to_style (xmlGetProp (node, "style"));
-       text_flag = !(g_strcasecmp (xmlGetProp (node, "text"), "false") == 0);
-       scale = g_strtod (xmlGetProp (node, "scale"), NULL);
+       /* size attrs */
+       w = lgl_xml_get_prop_length (node, "w", 0);
+       h = lgl_xml_get_prop_length (node, "h", 0);
+       gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h);
+
+       /* prop attrs */
+       id = lgl_xml_get_prop_string (node, "style", NULL);
+       text_flag = lgl_xml_get_prop_boolean (node, "text", FALSE);
+       checksum_flag = lgl_xml_get_prop_boolean (node, "checksum", TRUE);
+       format_digits = lgl_xml_get_prop_uint (node, "format", 10);
+       gl_label_barcode_set_props (GL_LABEL_BARCODE(object),
+                                   (gchar *)id, text_flag, checksum_flag, format_digits);
+       g_free (id);
+       
+       color_node = gl_color_node_new_default ();
+       string = lgl_xml_get_prop_string (node, "color_field", NULL);
+       if ( string ) {
+               color_node->field_flag = TRUE;
+               color_node->key = string;
+       } else {
+               color_node->color = lgl_xml_get_prop_uint (node, "color", 0);           
+       }
+       gl_label_object_set_line_color (GL_LABEL_OBJECT(object), color_node);
+       gl_color_node_free (&color_node);
 
-       child = node->xmlChildrenNode;
-       text_node = g_new0 (glTextNode, 1);
-       if (g_strcasecmp (child->name, "Field") == 0) {
-               text_node->field_flag = TRUE;
-               text_node->data = xmlGetProp (child, "name");
-       } else if (xmlNodeIsText (child)) {
+       /* data or field attr */
+       string = lgl_xml_get_prop_string (node, "data", NULL);
+       if ( string ) {
+               text_node = g_new0 (glTextNode, 1);
                text_node->field_flag = FALSE;
-               text_node->data = xmlNodeGetContent (child);
+               text_node->data = string;
+               gl_label_barcode_set_data (GL_LABEL_BARCODE(object), text_node);
+               gl_text_node_free (&text_node);
        } else {
-               g_warning ("Unexpected Barcode child: \"%s\"", child->name);
+               string = lgl_xml_get_prop_string (node, "field", NULL);
+               if ( string ) {
+                       text_node = g_new0 (glTextNode, 1);
+                       text_node->field_flag = TRUE;
+                       text_node->data = string;
+                       gl_label_barcode_set_data (GL_LABEL_BARCODE(object), text_node);
+                       gl_text_node_free (&text_node);
+               } else {
+                       g_message ("Missing Object-barcode data or field attr");
+               }
        }
 
-       gl_label_barcode_set_data (GL_LABEL_BARCODE(object), text_node);
-       gl_label_barcode_set_props (GL_LABEL_BARCODE(object),
-                                   style, text_flag, color, scale);
+       /* affine attrs */
+       xml_parse_affine_attrs (node, GL_LABEL_OBJECT(object));
 
-       gl_text_node_free (&text_node);
+       /* shadow attrs */
+       xml_parse_shadow_attrs (node, GL_LABEL_OBJECT(object));
 
        gl_debug (DEBUG_XML, "END");
-
-       return GL_LABEL_OBJECT(object);
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Parse XML merge fields tag.                                */
+/* PRIVATE.  Parse XML merge fields tag.                                    */
 /*--------------------------------------------------------------------------*/
 static void
-xml_parse_merge_fields (xmlNodePtr node,
-                       glLabel label)
+xml_parse_merge_fields (xmlNodePtr  node,
+                       glLabel    *label)
 {
-       xmlNodePtr  child;
+       gchar      *string;
        glMerge    *merge;
-       gchar      *src;
 
        gl_debug (DEBUG_XML, "START");
 
-       merge = gl_merge_new (xmlGetProp (node, "type"));
-       src = xmlGetProp (node, "src");
-       gl_merge_set_src (merge, src);
+       string = lgl_xml_get_prop_string (node, "type", NULL);
+       merge = gl_merge_new (string);
+       g_free (string);
+
+       string = lgl_xml_get_prop_string (node, "src", NULL);
+       gl_merge_set_src (merge, string);
+       g_free (string);
 
        gl_label_set_merge (label, merge);
 
@@ -638,87 +829,337 @@ xml_parse_merge_fields (xmlNodePtr node,
        gl_debug (DEBUG_XML, "END");
 }
 
+
+/*--------------------------------------------------------------------------*/
+/* PRIVATE.  Parse XML data tag.                                            */
+/*--------------------------------------------------------------------------*/
+static void
+xml_parse_data (xmlNodePtr  node,
+               glLabel    *label)
+{
+       xmlNodePtr  child;
+
+       gl_debug (DEBUG_XML, "START");
+
+       for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
+
+               if (lgl_xml_is_node (child, "Pixdata")) {
+                       xml_parse_pixdata (child, label);
+               } else {
+                       if (!xmlNodeIsText (child)) {
+                               g_message (_("bad node in Data node =  \"%s\""),
+                                          child->name);
+                       }
+               }
+       }
+
+       gl_debug (DEBUG_XML, "END");
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* PRIVATE.  Parse XML pixbuf data tag.                                     */
+/*--------------------------------------------------------------------------*/
+static void
+xml_parse_pixdata (xmlNodePtr  node,
+                  glLabel    *label)
+{
+       gchar      *name, *base64;
+       guchar     *stream;
+       gsize       stream_length;
+       gboolean    ret;
+       GdkPixdata *pixdata;
+       GdkPixbuf  *pixbuf;
+       GHashTable *pixbuf_cache;
+
+       gl_debug (DEBUG_XML, "START");
+
+       name = lgl_xml_get_prop_string (node, "name", NULL);
+       base64 = lgl_xml_get_node_content (node);
+
+       stream = g_base64_decode ((gchar *)base64, &stream_length);
+       pixdata = g_new0 (GdkPixdata, 1);
+       ret = gdk_pixdata_deserialize (pixdata, stream_length, stream, NULL);
+
+       if (ret) {
+               pixbuf = gdk_pixbuf_from_pixdata (pixdata, TRUE, NULL);
+
+               pixbuf_cache = gl_label_get_pixbuf_cache (label);
+               gl_pixbuf_cache_add_pixbuf (pixbuf_cache, (gchar *)name, pixbuf);
+       }
+
+       g_free (name);
+       g_free (base64);
+
+       g_free (stream);
+       g_free (pixdata);
+
+       gl_debug (DEBUG_XML, "END");
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* PRIVATE.  Parse top-level Span tag.                                      */
+/*--------------------------------------------------------------------------*/
+static void
+xml_parse_toplevel_span  (xmlNodePtr        node,
+                         glLabelObject    *object)
+{
+       gchar            *font_family;
+       gdouble           font_size;
+       PangoWeight       font_weight;
+       gboolean          font_italic_flag;
+       glColorNode      *color_node;
+       gdouble           text_line_spacing;
+       gchar            *string;
+       GList            *lines, *text_nodes;
+       xmlNodePtr        child;
+       glTextNode       *text_node;
+
+       gl_debug (DEBUG_XML, "START");
+
+       /* Font family attr */
+       font_family = lgl_xml_get_prop_string (node, "font_family", "Sans");
+       gl_label_object_set_font_family (object, font_family);
+       g_free (font_family);
+
+       /* Font size attr */
+       font_size = lgl_xml_get_prop_double (node, "font_size", 0.0);
+       gl_label_object_set_font_size (object, font_size);
+
+       /* Font weight attr */
+       string = lgl_xml_get_prop_string (node, "font_weight", NULL);
+       font_weight = gl_util_string_to_weight (string);
+       g_free (string);
+       gl_label_object_set_font_weight (object, font_weight);
+
+       /* Font italic flag attr */
+       font_italic_flag = lgl_xml_get_prop_boolean (node, "font_italic", FALSE);
+       gl_label_object_set_font_italic_flag (object, font_italic_flag);
+
+       /* Text color attr */
+       color_node = gl_color_node_new_default ();
+       string = lgl_xml_get_prop_string (node, "color_field", NULL);
+       if ( string ) {
+               color_node->field_flag = TRUE;
+               color_node->key = string;
+       } else {
+               color_node->color = lgl_xml_get_prop_uint (node, "color", 0);           
+       }
+       gl_label_object_set_text_color (object, color_node);
+       gl_color_node_free (&color_node);
+       
+
+       /* Text line spacing attr  */
+       text_line_spacing = lgl_xml_get_prop_double (node, "line_spacing", 1.0);
+       gl_label_object_set_text_line_spacing (object, text_line_spacing); 
+
+       /* Now descend children, and build lines of text nodes */
+       lines = NULL;
+       text_nodes = NULL;
+       for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
+
+               if (xmlNodeIsText (child)) {
+                       gchar *data = lgl_xml_get_node_content (child); 
+
+                       /* Hack: if the first char is LF, it's an xml formatting string */
+                       if (data[0] != '\n') { 
+                               /* Literal text */
+                               text_node = g_new0 (glTextNode, 1);
+                               text_node->field_flag = FALSE;
+                               text_node->data = g_strdup ((gchar *)data);
+                               text_nodes = g_list_append (text_nodes, text_node);
+                       }
+                       g_free (data);
+
+               } else if (lgl_xml_is_node (child, "Span")) {
+
+                       g_message ("Unexpected rich text (not supported, yet!)");
+
+               } else if (lgl_xml_is_node (child, "Field")) {
+
+                       /* Field node */
+                       string = lgl_xml_get_prop_string (child, "name", NULL);
+                       text_node = g_new0 (glTextNode, 1);
+                       text_node->field_flag = TRUE;
+                       text_node->data = string;
+                       text_nodes = g_list_append (text_nodes, text_node);
+
+               } else if (lgl_xml_is_node (child, "NL")) {
+
+                       /* Store line. */
+                       lines = g_list_append (lines, text_nodes);
+                       text_nodes = NULL;
+
+               } else {
+                       g_message ("Unexpected Span child: \"%s\"", child->name);
+               }
+
+       }
+       if ( text_nodes ) {
+               /* Store last line. */
+               lines = g_list_append (lines, text_nodes);
+               text_nodes = NULL;
+       }
+       gl_label_text_set_lines (GL_LABEL_TEXT(object), lines);
+       gl_text_node_lines_free (&lines);
+
+       gl_debug (DEBUG_XML, "END");
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* PRIVATE.  Parse affine attributes.                                       */
+/*--------------------------------------------------------------------------*/
+static void
+xml_parse_affine_attrs (xmlNodePtr        node,
+                       glLabelObject    *object)
+{
+       gdouble           a[6];
+        cairo_matrix_t    matrix;
+
+       a[0] = lgl_xml_get_prop_double (node, "a0", 0.0);
+       a[1] = lgl_xml_get_prop_double (node, "a1", 0.0);
+       a[2] = lgl_xml_get_prop_double (node, "a2", 0.0);
+       a[3] = lgl_xml_get_prop_double (node, "a3", 0.0);
+       a[4] = lgl_xml_get_prop_double (node, "a4", 0.0);
+       a[5] = lgl_xml_get_prop_double (node, "a5", 0.0);
+
+        cairo_matrix_init (&matrix, a[0], a[1], a[2], a[3], a[4], a[5]);
+
+       gl_label_object_set_matrix (object, &matrix);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* PRIVATE.  Parse shadow attributes.                                       */
+/*--------------------------------------------------------------------------*/
+static void
+xml_parse_shadow_attrs (xmlNodePtr        node,
+                       glLabelObject    *object)
+{
+       gboolean         shadow_state;
+       gdouble          shadow_x;
+       gdouble          shadow_y;
+       glColorNode     *shadow_color_node;
+       gdouble          shadow_opacity;
+       gchar           *string;
+
+       shadow_state = lgl_xml_get_prop_boolean (node, "shadow", FALSE);
+       gl_label_object_set_shadow_state (object, shadow_state);
+
+       if (shadow_state)
+       {
+               shadow_x = lgl_xml_get_prop_length (node, "shadow_x", 0.0);
+               shadow_y = lgl_xml_get_prop_length (node, "shadow_y", 0.0);
+               gl_label_object_set_shadow_offset (object, shadow_x, shadow_y);
+               
+               shadow_color_node = gl_color_node_new_default ();
+               string = lgl_xml_get_prop_string (node, "shadow_color_field", NULL);
+               if ( string ) {
+                       shadow_color_node->field_flag = TRUE;
+                       shadow_color_node->key = string;
+               } else {
+                       shadow_color_node->color = lgl_xml_get_prop_uint (node, "shadow_color", 0);             
+               }
+               gl_label_object_set_shadow_color (object, shadow_color_node);
+               gl_color_node_free (&shadow_color_node);
+
+               shadow_opacity = lgl_xml_get_prop_double (node, "shadow_opacity", 1.0);
+               gl_label_object_set_shadow_opacity (object, shadow_opacity);
+       }
+}
+
+
 /****************************************************************************/
 /* Save label to xml label file.                                            */
 /****************************************************************************/
 void
-gl_xml_label_save (glLabel *label,
-                  const gchar *filename,
+gl_xml_label_save (glLabel          *label,
+                  const gchar      *utf8_filename,
                   glXMLLabelStatus *status)
 {
        xmlDocPtr doc;
-       gint xml_ret;
+       gint      xml_ret;
+       gchar     *filename;
 
        gl_debug (DEBUG_XML, "START");
 
        doc = xml_label_to_doc (label, status);
 
-       xml_ret = xmlSaveFormatFile (filename, doc, TRUE);
-       xmlFreeDoc (doc);
-       if (xml_ret == -1) {
+       filename = g_filename_from_utf8 (utf8_filename, -1, NULL, NULL, NULL);
+       if (!filename)
+               g_message (_("Utf8 conversion error."));
+       else {
+               xmlSetDocCompressMode (doc, gl_label_get_compression (label));
+               xml_ret = xmlSaveFormatFile (filename, doc, TRUE);
+               xmlFreeDoc (doc);
+               if (xml_ret == -1) {
 
-               g_warning (_("Problem saving xml file."));
-               *status = XML_LABEL_ERROR_SAVE_FILE;
+                       g_message (_("Problem saving xml file."));
+                       *status = XML_LABEL_ERROR_SAVE_FILE;
 
-       } else {
+               } else {
 
-               gl_label_set_filename (label, filename);
-               gl_label_clear_modified (label);
+                       gl_label_set_filename (label, utf8_filename);
+                       gl_label_clear_modified (label);
 
+               }
+               g_free (filename);
        }
 
        gl_debug (DEBUG_XML, "END");
 }
 
+
 /****************************************************************************/
 /* Save label to xml buffer.                                                */
 /****************************************************************************/
 gchar *
-gl_xml_label_save_buffer (glLabel *label,
+gl_xml_label_save_buffer (glLabel          *label,
                          glXMLLabelStatus *status)
 {
-       xmlDocPtr doc;
-       gint size;
-       gchar *buffer;
+       xmlDocPtr  doc;
+       gint       size;
+       guchar    *buffer;
 
        gl_debug (DEBUG_XML, "START");
 
        doc = xml_label_to_doc (label, status);
 
-       xmlDocDumpMemory (doc, (xmlChar **)&buffer, &size);
+       xmlDocDumpMemory (doc, &buffer, &size);
        xmlFreeDoc (doc);
 
        gl_label_clear_modified (label);
 
        gl_debug (DEBUG_XML, "END");
 
-       return buffer;
+       return (gchar *)buffer;
 }
 
+
 /*--------------------------------------------------------------------------*/
 /* PRIVATE.  Convert label to xml doc structure.                            */
 /*--------------------------------------------------------------------------*/
 static xmlDocPtr
-xml_label_to_doc (glLabel label,
+xml_label_to_doc (glLabel          *label,
                  glXMLLabelStatus *status)
 {
-       xmlDocPtr doc;
-       xmlNsPtr ns;
-       glTemplate *template;
-       glMerge *merge;
+       xmlDocPtr   doc;
+       xmlNsPtr    ns;
+       glMerge    *merge;
 
        gl_debug (DEBUG_XML, "START");
 
        LIBXML_TEST_VERSION;
 
-       doc = xmlNewDoc ("1.0");
-       doc->xmlRootNode = xmlNewDocNode (doc, NULL, "Document", NULL);
+       doc = xmlNewDoc ((xmlChar *)"1.0");
+       doc->xmlRootNode = xmlNewDocNode (doc, NULL, (xmlChar *)"Glabels-document", NULL);
 
-       ns = xmlNewNs (doc->xmlRootNode, NAME_SPACE, "glabels");
+       ns = xmlNewNs (doc->xmlRootNode, (xmlChar *)LGL_XML_NAME_SPACE, NULL);
        xmlSetNs (doc->xmlRootNode, ns);
 
-       template = gl_label_get_template (label);
-       gl_template_xml_add_sheet (template, doc->xmlRootNode, ns);
+       lgl_xml_template_create_template_node (label->template, doc->xmlRootNode, ns);
 
        xml_create_objects (doc->xmlRootNode, ns, label);
 
@@ -726,8 +1167,10 @@ xml_label_to_doc (glLabel * label,
        gl_debug (DEBUG_XML, "merge=%p", merge);
        if (merge != NULL) {
                xml_create_merge_fields (doc->xmlRootNode, ns, label);
+               g_object_unref (G_OBJECT(merge));
        }
-       g_object_unref (G_OBJECT(merge));
+
+       xml_create_data (doc->xmlRootNode, ns, label);
 
        gl_debug (DEBUG_XML, "END");
 
@@ -735,411 +1178,656 @@ xml_label_to_doc (glLabel * label,
        return doc;
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Add XML Label->Objects Node                                    */
+/* PRIVATE.  Add XML Objects Node                                           */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_objects (xmlNodePtr root,
-                   xmlNsPtr ns,
-                   glLabel label)
+xml_create_objects (xmlNodePtr  root,
+                   xmlNsPtr    ns,
+                   glLabel    *label)
 {
-       xmlNodePtr node;
-       gboolean rotate_flag;
-       GList *p;
+       xmlNodePtr     node;
+       GList         *p;
+       glLabelObject *object;
 
        gl_debug (DEBUG_XML, "START");
 
-       rotate_flag = gl_label_get_rotate_flag (label);
-
-       node = xmlNewChild (root, ns, "Objects", NULL);
-       xmlSetProp (node, "id", "0");
-       xmlSetProp (node, "rotate", rotate_flag ? "True" : "False");
+       node = xmlNewChild (root, ns, (xmlChar *)"Objects", NULL);
+       lgl_xml_set_prop_string (node, "id", "0");
+       lgl_xml_set_prop_boolean (node, "rotate", label->rotate_flag);
 
        for (p = label->objects; p != NULL; p = p->next) {
-               xml_create_object (node, ns, GL_LABEL_OBJECT(p->data));
+
+               object = GL_LABEL_OBJECT(p->data);
+
+               if ( GL_IS_LABEL_TEXT(object) ) {
+                       xml_create_object_text (node, ns, object);
+               } else if ( GL_IS_LABEL_BOX(object) ) {
+                       xml_create_object_box (node, ns, object);
+               } else if ( GL_IS_LABEL_ELLIPSE(object) ) {
+                       xml_create_object_ellipse (node, ns, object);
+               } else if ( GL_IS_LABEL_LINE(object) ) {
+                       xml_create_object_line (node, ns, object);
+               } else if ( GL_IS_LABEL_IMAGE(object) ) {
+                       xml_create_object_image (node, ns, object);
+               } else if ( GL_IS_LABEL_BARCODE(object) ) {
+                       xml_create_object_barcode (node, ns, object);
+               } else {
+                       g_message ("Unknown label object");
+               }
+
        }
 
        gl_debug (DEBUG_XML, "END");
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Add XML label object Node                                      */
+/* PRIVATE.  Add XML Objects->Object-text Node                              */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_object (xmlNodePtr root,
-                  xmlNsPtr ns,
-                  glLabelObject * object)
+xml_create_object_text (xmlNodePtr     root,
+                       xmlNsPtr       ns,
+                       glLabelObject *object)
 {
-       xmlNodePtr  object_node;
-       gdouble     x, y;
-       gchar      *string;
-       gdouble     affine[6];
+       xmlNodePtr        node;
+       gdouble           x, y;
+       gdouble           w, h;
+       PangoAlignment    align;
+       gboolean          auto_shrink;
 
        gl_debug (DEBUG_XML, "START");
 
-       object_node = xmlNewChild (root, ns, "Object", NULL);
+       node = xmlNewChild (root, ns, (xmlChar *)"Object-text", NULL);
 
+       /* position attrs */
        gl_label_object_get_position (object, &x, &y);
-       string = g_strdup_printf ("%g", x);
-       xmlSetProp (object_node, "x", string);
-       g_free (string);
-       string = g_strdup_printf ("%g", y);
-       xmlSetProp (object_node, "y", string);
-       g_free (string);
+       lgl_xml_set_prop_length (node, "x", x);
+       lgl_xml_set_prop_length (node, "y", y);
 
-       gl_label_object_get_affine (object, affine);
-       string = g_strdup_printf ("%g", affine[0]);
-       xmlSetProp (object_node, "a0", string);
-       g_free (string);
-       string = g_strdup_printf ("%g", affine[1]);
-       xmlSetProp (object_node, "a1", string);
-       g_free (string);
-       string = g_strdup_printf ("%g", affine[2]);
-       xmlSetProp (object_node, "a2", string);
-       g_free (string);
-       string = g_strdup_printf ("%g", affine[3]);
-       xmlSetProp (object_node, "a3", string);
-       g_free (string);
-       string = g_strdup_printf ("%g", affine[4]);
-       xmlSetProp (object_node, "a4", string);
-       g_free (string);
-       string = g_strdup_printf ("%g", affine[5]);
-       xmlSetProp (object_node, "a5", string);
-       g_free (string);
+       /* size attrs */
+       gl_label_object_get_raw_size ( object, &w, &h);
+       lgl_xml_set_prop_length (node, "w", w);
+       lgl_xml_set_prop_length (node, "h", h);
 
-       if ( GL_IS_LABEL_TEXT(object) ) {
-               xml_create_text_props (object_node, ns, object);
-       } else if ( GL_IS_LABEL_BOX(object) ) {
-               xml_create_box_props (object_node, ns, object);
-       } else if ( GL_IS_LABEL_LINE(object) ) {
-               xml_create_line_props (object_node, ns, object);
-       } else if ( GL_IS_LABEL_ELLIPSE(object) ) {
-               xml_create_ellipse_props (object_node, ns, object);
-       } else if ( GL_IS_LABEL_IMAGE(object) ) {
-               xml_create_image_props (object_node, ns, object);
-       } else if ( GL_IS_LABEL_BARCODE(object) ) {
-               xml_create_barcode_props (object_node, ns, object);
-       } else {
-               g_warning ("Unknown label object");
-       }
+       /* justify attr */
+       align = gl_label_object_get_text_alignment (object);
+       lgl_xml_set_prop_string (node, "justify", gl_util_align_to_string (align));
+
+       /* auto_shrink attr */
+       auto_shrink = gl_label_text_get_auto_shrink (GL_LABEL_TEXT (object));
+       lgl_xml_set_prop_boolean (node, "auto_shrink", auto_shrink);
+
+       /* affine attrs */
+       xml_create_affine_attrs (node, object);
+
+       /* shadow attrs */
+       xml_create_shadow_attrs (node, object);
+
+       /* Add children */
+       xml_create_toplevel_span (node, ns, GL_LABEL_TEXT(object));
 
        gl_debug (DEBUG_XML, "END");
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Add XML Label->Text Node Properties                            */
+/* PRIVATE.  Add XML Objects->Object-box Node                               */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_text_props (xmlNodePtr object_node,
-                      xmlNsPtr ns,
-                      glLabelObject * object)
+xml_create_object_box (xmlNodePtr     root,
+                      xmlNsPtr       ns,
+                      glLabelObject *object)
 {
-       xmlNodePtr line_node, field_node, literal_node;
-       GList *lines;
-       gchar *font_family;
-       gdouble font_size;
-       GnomeFontWeight font_weight;
-       gboolean font_italic_flag;
-       guint color;
-       GtkJustification just;
-       gchar *string;
-       GList *p_line, *p_node;
-       glTextNode *node_text;
+       xmlNodePtr        node;
+       gdouble           x, y;
+       gdouble           w, h;
+       gdouble           line_width;
+       glColorNode      *line_color_node;
+       glColorNode *fill_color_node;
 
        gl_debug (DEBUG_XML, "START");
 
-       xmlSetProp (object_node, "type", "Text");
+       node = xmlNewChild (root, ns, (xmlChar *)"Object-box", NULL);
 
-       lines = gl_label_text_get_lines (GL_LABEL_TEXT(object));
-       gl_label_text_get_props (GL_LABEL_TEXT(object),
-                                &font_family, &font_size, &font_weight,
-                                &font_italic_flag,
-                                &color, &just);
+       /* position attrs */
+       gl_label_object_get_position (object, &x, &y);
+       lgl_xml_set_prop_length (node, "x", x);
+       lgl_xml_set_prop_length (node, "y", y);
+
+       /* size attrs */
+       gl_label_object_get_size (object, &w, &h);
+       lgl_xml_set_prop_length (node, "w", w);
+       lgl_xml_set_prop_length (node, "h", h);
+
+       /* line attrs */
+       line_width = gl_label_object_get_line_width (GL_LABEL_OBJECT(object));
+       lgl_xml_set_prop_length (node, "line_width", line_width);
+       
+       line_color_node = gl_label_object_get_line_color (GL_LABEL_OBJECT(object));
+       if (line_color_node->field_flag)
+       {
+               lgl_xml_set_prop_string (node, "line_color_field", line_color_node->key);
+       }
+       else
+       {
+               lgl_xml_set_prop_uint_hex (node, "line_color", line_color_node->color);
+       }
+       gl_color_node_free (&line_color_node);
 
-       xmlSetProp (object_node, "font_family", font_family);
-       string = g_strdup_printf ("%g", font_size);
-       xmlSetProp (object_node, "font_size", string);
-       g_free (string);
-       xmlSetProp (object_node, "font_weight",
-                   gl_util_weight_to_string (font_weight));
-       xmlSetProp (object_node, "font_italic",
-                   font_italic_flag?"True":"False");
+       /* fill attrs (color or field) */
+       fill_color_node = gl_label_object_get_fill_color (GL_LABEL_OBJECT(object));
+       if (fill_color_node->field_flag)
+       {
+               lgl_xml_set_prop_string (node, "fill_color_field", fill_color_node->key);
+       }
+       else
+       {
+               lgl_xml_set_prop_uint_hex (node, "fill_color", fill_color_node->color);
+       }
+       gl_color_node_free (&fill_color_node);
 
-       xmlSetProp (object_node, "justify", gl_util_just_to_string (just));
+       /* affine attrs */
+       xml_create_affine_attrs (node, object);
 
-       string = g_strdup_printf ("0x%08x", color);
-       xmlSetProp (object_node, "color", string);
-       g_free (string);
+       /* shadow attrs */
+       xml_create_shadow_attrs (node, object);
 
-       for (p_line = lines; p_line != NULL; p_line = p_line->next) {
-               line_node = xmlNewChild (object_node, ns, "Line", NULL);
+       gl_debug (DEBUG_XML, "END");
+}
 
-               for (p_node = (GList *) p_line->data; p_node != NULL;
-                    p_node = p_node->next) {
-                       node_text = (glTextNode *) p_node->data;
 
-                       if (node_text->field_flag) {
-                               field_node =
-                                   xmlNewChild (line_node, ns, "Field", NULL);
-                               xmlSetProp (field_node, "name",
-                                           node_text->data);
-                       } else {
-                               literal_node =
-                                   xmlNewChild (line_node, ns,
-                                                "Literal", node_text->data);
-                       }
+/*--------------------------------------------------------------------------*/
+/* PRIVATE.  Add XML Objects->Object-ellipse Node                           */
+/*--------------------------------------------------------------------------*/
+static void
+xml_create_object_ellipse (xmlNodePtr     root,
+                          xmlNsPtr       ns,
+                          glLabelObject *object)
+{
+       xmlNodePtr        node;
+       gdouble           x, y;
+       gdouble           w, h;
+       gdouble           line_width;
+       glColorNode      *line_color_node;
+       glColorNode *fill_color_node;
 
-               }
+       gl_debug (DEBUG_XML, "START");
+
+       node = xmlNewChild (root, ns, (xmlChar *)"Object-ellipse", NULL);
 
+       /* position attrs */
+       gl_label_object_get_position (object, &x, &y);
+       lgl_xml_set_prop_length (node, "x", x);
+       lgl_xml_set_prop_length (node, "y", y);
+
+       /* size attrs */
+       gl_label_object_get_size (object, &w, &h);
+       lgl_xml_set_prop_length (node, "w", w);
+       lgl_xml_set_prop_length (node, "h", h);
+
+       /* line attrs */
+       line_width = gl_label_object_get_line_width (GL_LABEL_OBJECT(object));
+       lgl_xml_set_prop_length (node, "line_width", line_width);
+       
+       line_color_node = gl_label_object_get_line_color (GL_LABEL_OBJECT(object));
+       if (line_color_node->field_flag)
+       {
+               lgl_xml_set_prop_string (node, "line_color_field", line_color_node->key);
+       }
+       else
+       {
+               lgl_xml_set_prop_uint_hex (node, "line_color", line_color_node->color);
        }
+       gl_color_node_free (&line_color_node);
 
-       gl_text_node_lines_free (&lines);
-       g_free (font_family);
+
+       /* fill attrs (color or field) */
+       fill_color_node = gl_label_object_get_fill_color (GL_LABEL_OBJECT(object));
+       if (fill_color_node->field_flag)
+       {
+               lgl_xml_set_prop_string (node, "fill_color_field", fill_color_node->key);
+       }
+       else
+       {
+               lgl_xml_set_prop_uint_hex (node, "fill_color", fill_color_node->color);
+       }
+       gl_color_node_free (&fill_color_node);
+
+       /* affine attrs */
+       xml_create_affine_attrs (node, object);
+
+       /* shadow attrs */
+       xml_create_shadow_attrs (node, object);
 
        gl_debug (DEBUG_XML, "END");
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Add XML Label->Box Node Properties                             */
+/* PRIVATE.  Add XML Objects->Object-line Node                              */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_box_props (xmlNodePtr object_node,
-                     xmlNsPtr ns,
-                     glLabelObject * object)
+xml_create_object_line (xmlNodePtr     root,
+                       xmlNsPtr       ns,
+                       glLabelObject *object)
 {
-       gchar *string;
-       gdouble line_width;
-       guint line_color, fill_color;
-       gdouble w, h;
+       xmlNodePtr        node;
+       gdouble           x, y;
+       gdouble           dx, dy;
+       gdouble           line_width;
+       glColorNode      *line_color_node;
 
        gl_debug (DEBUG_XML, "START");
 
-       xmlSetProp (object_node, "type", "Box");
+       node = xmlNewChild (root, ns, (xmlChar *)"Object-line", NULL);
 
-       gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
-       line_width = gl_label_box_get_line_width (GL_LABEL_BOX(object));
-       line_color = gl_label_box_get_line_color (GL_LABEL_BOX(object));
-       fill_color = gl_label_box_get_fill_color (GL_LABEL_BOX(object));
+       /* position attrs */
+       gl_label_object_get_position (object, &x, &y);
+       lgl_xml_set_prop_length (node, "x", x);
+       lgl_xml_set_prop_length (node, "y", y);
+
+       /* length attrs */
+       gl_label_object_get_size (object, &dx, &dy);
+       lgl_xml_set_prop_length (node, "dx", dx);
+       lgl_xml_set_prop_length (node, "dy", dy);
+
+       /* line attrs */
+       line_width = gl_label_object_get_line_width (GL_LABEL_OBJECT(object));
+       lgl_xml_set_prop_length (node, "line_width", line_width);
+       
+       line_color_node = gl_label_object_get_line_color (GL_LABEL_OBJECT(object));
+       if (line_color_node->field_flag)
+       {
+               lgl_xml_set_prop_string (node, "line_color_field", line_color_node->key);
+       }
+       else
+       {
+               lgl_xml_set_prop_uint_hex (node, "line_color", line_color_node->color);
+       }
+       gl_color_node_free (&line_color_node);
 
-       string = g_strdup_printf ("%g", w);
-       xmlSetProp (object_node, "w", string);
-       g_free (string);
-       string = g_strdup_printf ("%g", h);
-       xmlSetProp (object_node, "h", string);
-       g_free (string);
 
-       string = g_strdup_printf ("%g", line_width);
-       xmlSetProp (object_node, "line_width", string);
-       g_free (string);
+       /* affine attrs */
+       xml_create_affine_attrs (node, object);
 
-       string = g_strdup_printf ("0x%08x", line_color);
-       xmlSetProp (object_node, "line_color", string);
-       g_free (string);
-
-       string = g_strdup_printf ("0x%08x", fill_color);
-       xmlSetProp (object_node, "fill_color", string);
-       g_free (string);
+       /* shadow attrs */
+       xml_create_shadow_attrs (node, object);
 
        gl_debug (DEBUG_XML, "END");
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Add XML Label->Line Node Properties                            */
+/* PRIVATE.  Add XML Objects->Object-image Node                             */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_line_props (xmlNodePtr object_node,
-                      xmlNsPtr ns,
-                      glLabelObject * object)
+xml_create_object_image (xmlNodePtr     root,
+                        xmlNsPtr       ns,
+                        glLabelObject *object)
 {
-       gchar *string;
-       gdouble line_width;
-       guint line_color;
-       gdouble w, h;
+       xmlNodePtr        node;
+       gdouble           x, y;
+       gdouble           w, h;
+       glTextNode       *filename;
 
        gl_debug (DEBUG_XML, "START");
 
-       xmlSetProp (object_node, "type", "Line");
+       node = xmlNewChild (root, ns, (xmlChar *)"Object-image", NULL);
 
-       gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
-       line_width = gl_label_line_get_line_width (GL_LABEL_LINE(object));
-       line_color = gl_label_line_get_line_color (GL_LABEL_LINE(object));
+       /* position attrs */
+       gl_label_object_get_position (object, &x, &y);
+       lgl_xml_set_prop_length (node, "x", x);
+       lgl_xml_set_prop_length (node, "y", y);
 
-       string = g_strdup_printf ("%g", w);
-       xmlSetProp (object_node, "dx", string);
-       g_free (string);
-       string = g_strdup_printf ("%g", h);
-       xmlSetProp (object_node, "dy", string);
-       g_free (string);
+       /* size attrs */
+       gl_label_object_get_size (object, &w, &h);
+       lgl_xml_set_prop_length (node, "w", w);
+       lgl_xml_set_prop_length (node, "h", h);
 
-       string = g_strdup_printf ("%g", line_width);
-       xmlSetProp (object_node, "line_width", string);
-       g_free (string);
+       /* src OR field attr */
+       filename = gl_label_image_get_filename (GL_LABEL_IMAGE(object));
+       if (filename->field_flag) {
+               lgl_xml_set_prop_string (node, "field", filename->data);
+       } else {
+               lgl_xml_set_prop_string (node, "src", filename->data);
+       }
+       gl_text_node_free (&filename);
 
-       string = g_strdup_printf ("0x%08x", line_color);
-       xmlSetProp (object_node, "line_color", string);
-       g_free (string);
+       /* affine attrs */
+       xml_create_affine_attrs (node, object);
+
+       /* shadow attrs */
+       xml_create_shadow_attrs (node, object);
 
        gl_debug (DEBUG_XML, "END");
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Add XML Label->Ellipse Node Properties                         */
+/* PRIVATE.  Add XML Objects->Object-barcode Node                           */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_ellipse_props (xmlNodePtr object_node,
-                         xmlNsPtr ns,
-                         glLabelObject * object)
+xml_create_object_barcode (xmlNodePtr     root,
+                          xmlNsPtr       ns,
+                          glLabelObject *object)
 {
-       gchar *string;
-       gdouble line_width;
-       guint line_color, fill_color;
-       gdouble w, h;
+       xmlNodePtr        node;
+       gdouble           x, y;
+       gdouble           w, h;
+       glTextNode       *text_node;
+       gchar            *id;
+       gboolean          text_flag;
+       gboolean          checksum_flag;
+       glColorNode      *color_node;
+       guint             format_digits;
 
        gl_debug (DEBUG_XML, "START");
 
-       xmlSetProp (object_node, "type", "Ellipse");
+       node = xmlNewChild (root, ns, (xmlChar *)"Object-barcode", NULL);
 
-       gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
-       line_width = gl_label_ellipse_get_line_width (GL_LABEL_ELLIPSE(object));
-       line_color = gl_label_ellipse_get_line_color (GL_LABEL_ELLIPSE(object));
-       fill_color = gl_label_ellipse_get_fill_color (GL_LABEL_ELLIPSE(object));
+       /* position attrs */
+       gl_label_object_get_position (object, &x, &y);
+       lgl_xml_set_prop_length (node, "x", x);
+       lgl_xml_set_prop_length (node, "y", y);
 
-       string = g_strdup_printf ("%g", w);
-       xmlSetProp (object_node, "w", string);
-       g_free (string);
-       string = g_strdup_printf ("%g", h);
-       xmlSetProp (object_node, "h", string);
-       g_free (string);
+       /* size attrs */
+       gl_label_object_get_raw_size (object, &w, &h);
+       lgl_xml_set_prop_length (node, "w", w);
+       lgl_xml_set_prop_length (node, "h", h);
 
-       string = g_strdup_printf ("%g", line_width);
-       xmlSetProp (object_node, "line_width", string);
-       g_free (string);
+       /* Barcode properties attrs */
+       gl_label_barcode_get_props (GL_LABEL_BARCODE(object),
+                                   &id, &text_flag, &checksum_flag, &format_digits);
+       lgl_xml_set_prop_string (node, "style", id);
+       lgl_xml_set_prop_boolean (node, "text", text_flag);
+       lgl_xml_set_prop_boolean (node, "checksum", checksum_flag);
+       
+       g_free (id);
+       
+       color_node = gl_label_object_get_line_color (GL_LABEL_OBJECT(object));
+       if (color_node->field_flag)
+       {
+               lgl_xml_set_prop_string (node, "color_field", color_node->key);
+       }
+       else
+       {
+               lgl_xml_set_prop_uint_hex (node, "color", color_node->color);
+       }
+       gl_color_node_free (&color_node);
 
-       string = g_strdup_printf ("0x%08x", line_color);
-       xmlSetProp (object_node, "line_color", string);
-       g_free (string);
 
-       string = g_strdup_printf ("0x%08x", fill_color);
-       xmlSetProp (object_node, "fill_color", string);
-       g_free (string);
+       /* data OR field attr */
+       text_node = gl_label_barcode_get_data (GL_LABEL_BARCODE(object));
+       if (text_node->field_flag) {
+               lgl_xml_set_prop_string (node, "field", text_node->data);
+               lgl_xml_set_prop_int (node, "format", format_digits);
+       } else {
+               lgl_xml_set_prop_string (node, "data", text_node->data);
+       }
+       gl_text_node_free (&text_node);
+
+       /* affine attrs */
+       xml_create_affine_attrs (node, object);
+
+       /* shadow attrs */
+       xml_create_shadow_attrs (node, object);
 
        gl_debug (DEBUG_XML, "END");
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Add XML Label->Image Node Properties                           */
+/* PRIVATE.  Add XML Label Merge Fields Node                                */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_image_props (xmlNodePtr object_node,
-                       xmlNsPtr ns,
-                       glLabelObject * object)
+xml_create_merge_fields (xmlNodePtr  root,
+                        xmlNsPtr    ns,
+                        glLabel    *label)
 {
+       xmlNodePtr  node;
        gchar      *string;
-       gdouble     w, h;
-       glTextNode *filename;
-       xmlNodePtr  child;
+       glMerge    *merge;
 
        gl_debug (DEBUG_XML, "START");
 
-       xmlSetProp (object_node, "type", "Image");
+       merge = gl_label_get_merge (label);
 
-       gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
-       filename = gl_label_image_get_filename (GL_LABEL_IMAGE(object));
+       node = xmlNewChild (root, ns, (xmlChar *)"Merge", NULL);
 
-       string = g_strdup_printf ("%g", w);
-       xmlSetProp (object_node, "w", string);
+       string = gl_merge_get_name (merge);
+       lgl_xml_set_prop_string (node, "type", string);
        g_free (string);
-       string = g_strdup_printf ("%g", h);
-       xmlSetProp (object_node, "h", string);
+
+       string = gl_merge_get_src (merge);
+       lgl_xml_set_prop_string (node, "src", string);
        g_free (string);
 
-       if (filename->field_flag) {
-               child = xmlNewChild (object_node, ns, "Field", NULL);
-               xmlSetProp (child, "name", filename->data);
-       } else {
-               xmlNodeSetContent (object_node, filename->data);
+       g_object_unref (G_OBJECT(merge));
+
+       gl_debug (DEBUG_XML, "END");
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* PRIVATE.  Add XML Label Data Node                                        */
+/*--------------------------------------------------------------------------*/
+static void
+xml_create_data (xmlNodePtr  root,
+                xmlNsPtr    ns,
+                glLabel    *label)
+{
+       xmlNodePtr  node;
+       GList      *name_list, *p;
+       GHashTable *pixbuf_cache;
+
+       gl_debug (DEBUG_XML, "START");
+
+       node = xmlNewChild (root, ns, (xmlChar *)"Data", NULL);
+
+       pixbuf_cache = gl_label_get_pixbuf_cache (label);
+       name_list = gl_pixbuf_cache_get_name_list (pixbuf_cache);
+
+       for (p = name_list; p != NULL; p=p->next) {
+               xml_create_pixdata (node, ns, label, p->data);
        }
 
-       gl_text_node_free (&filename);
+       gl_pixbuf_cache_free_name_list (name_list);
+
 
        gl_debug (DEBUG_XML, "END");
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Add XML Label->Barcode Node Properties                         */
+/* PRIVATE.  Add XML Label Data Pixbuf Node                                 */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_barcode_props (xmlNodePtr object_node,
-                         xmlNsPtr ns,
-                         glLabelObject * object)
+xml_create_pixdata (xmlNodePtr  root,
+                   xmlNsPtr    ns,
+                   glLabel    *label,
+                   gchar      *name)
 {
-       glTextNode          *text_node;
-       glBarcodeStyle      style;
-       gboolean            text_flag;
-       guint               color;
-       gdouble             scale;
-       xmlNodePtr          child;
-       gchar              *string;
+       xmlNodePtr  node;
+       GHashTable *pixbuf_cache;
+       GdkPixbuf  *pixbuf;
+       GdkPixdata *pixdata;
+       guchar     *stream;
+       guint       stream_length;
+       gchar      *base64;
 
        gl_debug (DEBUG_XML, "START");
 
-       xmlSetProp (object_node, "type", "Barcode");
+       pixbuf_cache = gl_label_get_pixbuf_cache (label);
 
-       text_node = gl_label_barcode_get_data (GL_LABEL_BARCODE(object));
-       gl_label_barcode_get_props (GL_LABEL_BARCODE(object),
-                                   &style, &text_flag, &color, &scale);
+       pixbuf = gl_pixbuf_cache_get_pixbuf (pixbuf_cache, name);
+       if ( pixbuf != NULL ) {
 
-       string = g_strdup_printf ("0x%08x", color);
-       xmlSetProp (object_node, "color", string);
-       g_free (string);
+               pixdata = g_new0 (GdkPixdata, 1);
+               gdk_pixdata_from_pixbuf (pixdata, pixbuf, FALSE);
+               stream = gdk_pixdata_serialize (pixdata, &stream_length);
+               base64 = g_base64_encode (stream, stream_length);
 
-       xmlSetProp (object_node, "style", gl_barcode_style_to_text (style));
-       xmlSetProp (object_node, "text", text_flag?"True":"False");
-       string = g_strdup_printf ("%g", scale);
-       xmlSetProp (object_node, "scale", string);
-       g_free (string);
+               node = xmlNewChild (root, ns, (xmlChar *)"Pixdata", (xmlChar *)base64);
+               lgl_xml_set_prop_string (node, "name", name);
+               lgl_xml_set_prop_string (node, "encoding", "Base64");
 
-       if (text_node->field_flag) {
-               child = xmlNewChild (object_node, ns, "Field", NULL);
-               xmlSetProp (child, "name", text_node->data);
-       } else {
-               xmlNodeSetContent (object_node, text_node->data);
+               gl_pixbuf_cache_remove_pixbuf (pixbuf_cache, name);
+
+               g_free (pixdata);
+               g_free (stream);
+               g_free (base64);
        }
 
-       gl_text_node_free (&text_node);
 
        gl_debug (DEBUG_XML, "END");
 }
 
+
 /*--------------------------------------------------------------------------*/
-/* PRIVATE.  Add XML Label Merge Fields Node                                */
+/* PRIVATE.  Create top-level Span node.                                    */
 /*--------------------------------------------------------------------------*/
 static void
-xml_create_merge_fields (xmlNodePtr root,
-                            xmlNsPtr ns,
-                            glLabel * label)
+xml_create_toplevel_span (xmlNodePtr        root,
+                         xmlNsPtr          ns,
+                         glLabelText      *object_text)
 {
-       xmlNodePtr node, child;
-       gchar *string;
-       GList *p;
-       glMerge *merge;
+       xmlNodePtr        node;
+       gchar            *font_family;
+       gdouble           font_size;
+       PangoWeight       font_weight;
+       gboolean          font_italic_flag;
+       glColorNode      *color_node;
+       PangoAlignment    align;
+       gdouble           text_line_spacing;
+       GList            *lines, *p_line, *p_node;
+       glTextNode       *text_node;
+       xmlNodePtr        child;
+
+       node = xmlNewChild (root, ns, (xmlChar *)"Span", NULL);
+
+       /* All span attrs at top level. */
+       font_family = gl_label_object_get_font_family (GL_LABEL_OBJECT(object_text));
+       font_size = gl_label_object_get_font_size (GL_LABEL_OBJECT(object_text));
+       text_line_spacing = gl_label_object_get_text_line_spacing (GL_LABEL_OBJECT(object_text));
+       font_weight = gl_label_object_get_font_weight (GL_LABEL_OBJECT(object_text));
+       font_italic_flag = gl_label_object_get_font_italic_flag (GL_LABEL_OBJECT(object_text));
+       
+       color_node = gl_label_object_get_text_color (GL_LABEL_OBJECT(object_text));
+       if (color_node->field_flag)
+       {
+               lgl_xml_set_prop_string (node, "color_field", color_node->key);
+       }
+       else
+       {
+               lgl_xml_set_prop_uint_hex (node, "color", color_node->color);
+       }
+       gl_color_node_free (&color_node);
+       
+       align = gl_label_object_get_text_alignment (GL_LABEL_OBJECT(object_text));
+       lgl_xml_set_prop_string (node, "font_family", font_family);
+       lgl_xml_set_prop_double (node, "font_size", font_size);
+       lgl_xml_set_prop_string (node, "font_weight", gl_util_weight_to_string (font_weight));
+       lgl_xml_set_prop_boolean (node, "font_italic", font_italic_flag);
+       
+       lgl_xml_set_prop_double (node, "line_spacing", text_line_spacing);
+
+       /* Build children. */
+       lines = gl_label_text_get_lines (GL_LABEL_TEXT(object_text));
+       for (p_line = lines; p_line != NULL; p_line = p_line->next) {
 
-       gl_debug (DEBUG_XML, "START");
+               for (p_node = (GList *) p_line->data; p_node != NULL;
+                    p_node = p_node->next) {
+                       text_node = (glTextNode *) p_node->data;
 
-       merge = gl_label_get_merge (label);
+                       if (text_node->field_flag) {
+                               child = xmlNewChild (node, ns, (xmlChar *)"Field", NULL);
+                               lgl_xml_set_prop_string (child, "name", text_node->data);
+                       } else {
+                               xmlNodeAddContent (node, (xmlChar *)text_node->data);
+                       }
 
-       node = xmlNewChild (root, ns, "Merge_Fields", NULL);
+               }
 
-       string = gl_merge_get_name (merge);
-       xmlSetProp (node, "type", string);
-       g_free (string);
+               if ( p_line->next ) {
+                       child = xmlNewChild (node, ns, (xmlChar *)"NL", NULL);
+               }
 
-       string = gl_merge_get_src (merge);
-       xmlSetProp (node, "src", string);
-       g_free (string);
+       }
 
-       g_object_unref (G_OBJECT(merge));
+       gl_text_node_lines_free (&lines);
+       g_free (font_family);
 
-       gl_debug (DEBUG_XML, "END");
 }
 
+
+/*--------------------------------------------------------------------------*/
+/* PRIVATE.  Create affine attributes.                                      */
+/*--------------------------------------------------------------------------*/
+static void
+xml_create_affine_attrs (xmlNodePtr        node,
+                        glLabelObject    *object)
+{
+        cairo_matrix_t matrix;
+
+       gl_label_object_get_matrix (object, &matrix);
+
+       lgl_xml_set_prop_double (node, "a0", matrix.xx);
+       lgl_xml_set_prop_double (node, "a1", matrix.yx);
+       lgl_xml_set_prop_double (node, "a2", matrix.xy);
+       lgl_xml_set_prop_double (node, "a3", matrix.yy);
+       lgl_xml_set_prop_double (node, "a4", matrix.x0);
+       lgl_xml_set_prop_double (node, "a5", matrix.y0);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* PRIVATE.  Create shadow attributes.                                      */
+/*--------------------------------------------------------------------------*/
+static void
+xml_create_shadow_attrs (xmlNodePtr        node,
+                        glLabelObject    *object)
+{
+       gboolean          shadow_state;
+       gdouble           shadow_x;
+       gdouble           shadow_y;
+       glColorNode      *shadow_color_node;
+       gdouble           shadow_opacity;
+
+       shadow_state = gl_label_object_get_shadow_state (object);
+
+       if (shadow_state)
+       {
+               lgl_xml_set_prop_boolean (node, "shadow", shadow_state);
+
+               gl_label_object_get_shadow_offset (object, &shadow_x, &shadow_y);
+               lgl_xml_set_prop_length (node, "shadow_x", shadow_x);
+               lgl_xml_set_prop_length (node, "shadow_y", shadow_y);
+               
+               shadow_color_node = gl_label_object_get_shadow_color (object);
+               if (shadow_color_node->field_flag)
+               {
+                       lgl_xml_set_prop_string (node, "shadow_color_field", shadow_color_node->key);
+               }
+               else
+               {
+                       lgl_xml_set_prop_uint_hex (node, "shadow_color", shadow_color_node->color);
+               }
+               gl_color_node_free (&shadow_color_node);
+
+               shadow_opacity = gl_label_object_get_shadow_opacity (object);
+               lgl_xml_set_prop_double (node, "shadow_opacity", shadow_opacity);
+       }
+}
+
+
+
+/*
+ * Local Variables:       -- emacs
+ * mode: C                -- emacs
+ * c-basic-offset: 8      -- emacs
+ * tab-width: 8           -- emacs
+ * indent-tabs-mode: nil  -- emacs
+ * End:                   -- emacs
+ */