Converted README to markdown
[rox-filer.git] / ROX-Filer / src / xml.c
blob85628fde8925aa7277698e74592fc60da0ecd8d0
1 /*
2 * ROX-Filer, filer for the ROX desktop project
3 * Copyright (C) 2006, Thomas Leonard and others (see changelog for details).
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place, Suite 330, Boston, MA 02111-1307 USA
20 /* xml.c - A GObject wrapper for libxml documents */
22 #include "config.h"
24 #include <string.h>
26 #include <libxml/parser.h>
28 #include "global.h"
30 #include "i18n.h"
31 #include "xml.h"
33 static gpointer parent_class = NULL;
35 /* Static prototypes */
36 static xmlNode *best_lang(xmlNode *first);
37 static void xml_wrapper_finialize(GObject *object);
38 static void xml_wrapper_class_init(gpointer gclass, gpointer data);
39 static void xml_wrapper_init(GTypeInstance *object, gpointer gclass);
40 static GType xml_wrapper_get_type(void);
42 /****************************************************************
43 * EXTERNAL INTERFACE *
44 ****************************************************************/
46 XMLwrapper *xml_new(const char *pathname)
48 xmlDocPtr doc = NULL;
49 XMLwrapper *xml_data;
51 if (pathname)
53 doc = xmlParseFile(pathname);
54 if (!doc)
55 return NULL; /* Bad XML */
58 xml_data = g_object_new(xml_wrapper_get_type(), NULL);
59 xml_data->doc = doc;
61 return xml_data;
64 /* Return the first child of the root node with this name */
65 xmlNode *xml_get_section(XMLwrapper *xml, const gchar *ns, const gchar *name)
67 g_return_val_if_fail(xml != NULL, NULL);
68 g_return_val_if_fail(xml->doc != NULL, NULL);
70 return get_subnode(xmlDocGetRootElement(xml->doc), ns, name);
73 /* Return the (first) child of this node with the given name.
74 * NULL if not found.
75 * If there are several consecutive nodes with the same name but different
76 * xml:lang attributes, then the one matching the current locale is used,
77 * or the first one if none match.
79 xmlNode *get_subnode(xmlNode *node, const char *namespaceURI, const char *name)
81 for (node = node->xmlChildrenNode; node; node = node->next)
83 if (node->type != XML_ELEMENT_NODE)
84 continue;
86 if (strcmp(node->name, name))
87 continue;
89 if (node->ns == NULL || namespaceURI == NULL)
91 if (node->ns == NULL && namespaceURI == NULL)
92 return best_lang(node);
93 continue;
96 if (strcmp(node->ns->href, namespaceURI) == 0)
97 return best_lang(node);
100 return NULL;
103 /****************************************************************
104 * INTERNAL FUNCTIONS *
105 ****************************************************************/
107 /* Taking this node and each directly following node with the same name,
108 * return the one which matches the current LANG.
109 * Return the node itself if nothing matches.
111 static xmlNode *best_lang(xmlNode *first)
113 xmlNode *node = first;
114 xmlNode *fallback = NULL;
115 const char *target_lang = current_lang ? current_lang : "en";
116 char *territory;
118 g_return_val_if_fail(first != NULL, NULL);
120 territory = strchr(target_lang, '_');
122 for (node = first->next; node; node = node->next)
124 char *lang;
126 if (node->type != XML_ELEMENT_NODE)
127 continue;
129 /* Check names match... */
130 if (strcmp(node->name, first->name))
131 break;
133 /* Check namespaces match... */
134 if ((node->ns == NULL) != (first->ns == NULL))
135 break;
137 if (node->ns && first->ns)
138 if (strcmp(node->ns->href, first->ns->href))
139 break;
141 lang = xmlNodeGetLang(node);
143 if (!lang)
144 continue;
145 if (strcmp(lang, target_lang) == 0)
147 g_free(lang);
148 return node;
150 if (territory && strlen(lang) == (territory - target_lang) &&
151 strncmp(lang, target_lang, territory - target_lang) == 0)
153 fallback = node;
155 g_free(lang);
158 return fallback ? fallback : first;
161 static void xml_wrapper_finialize(GObject *object)
163 XMLwrapper *xml = (XMLwrapper *) object;
165 if (xml->doc)
167 xmlFreeDoc(xml->doc);
168 xml->doc = NULL;
171 G_OBJECT_CLASS(parent_class)->finalize(object);
174 static void xml_wrapper_class_init(gpointer gclass, gpointer data)
176 GObjectClass *object = (GObjectClass *) gclass;
178 parent_class = g_type_class_peek_parent(gclass);
180 object->finalize = xml_wrapper_finialize;
183 static void xml_wrapper_init(GTypeInstance *object, gpointer gclass)
185 XMLwrapper *wrapper = (XMLwrapper *) object;
187 wrapper->doc = NULL;
190 static GType xml_wrapper_get_type(void)
192 static GType type = 0;
194 if (!type)
196 static const GTypeInfo info =
198 sizeof (XMLwrapperClass),
199 NULL, /* base_init */
200 NULL, /* base_finalise */
201 xml_wrapper_class_init,
202 NULL, /* class_finalise */
203 NULL, /* class_data */
204 sizeof(XMLwrapper),
205 0, /* n_preallocs */
206 xml_wrapper_init
209 type = g_type_register_static(G_TYPE_OBJECT, "XMLwrapper",
210 &info, 0);
213 return type;