r1996: Cope slightly better with invalid filenames in various places (reported by
[rox-filer.git] / ROX-Filer / src / xml.c
blobcb3e692ed3f5bba0120105de7b0e095309bd5175
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2002, the ROX-Filer team.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* xml.c - A GObject wrapper for libxml documents */
24 #include "config.h"
26 #include <string.h>
28 #include <libxml/parser.h>
30 #include "global.h"
32 #include "i18n.h"
33 #include "xml.h"
35 static gpointer parent_class = NULL;
37 /* Static prototypes */
38 static xmlNode *best_lang(xmlNode *first);
39 static void xml_wrapper_finialize(GObject *object);
40 static void xml_wrapper_class_init(gpointer gclass, gpointer data);
41 static void xml_wrapper_init(GTypeInstance *object, gpointer gclass);
42 static GType xml_wrapper_get_type(void);
44 /****************************************************************
45 * EXTERNAL INTERFACE *
46 ****************************************************************/
48 XMLwrapper *xml_new(const char *pathname)
50 xmlDocPtr doc = NULL;
51 XMLwrapper *xml_data;
53 if (pathname)
55 doc = xmlParseFile(pathname);
56 if (!doc)
57 return NULL; /* Bad XML */
60 xml_data = g_object_new(xml_wrapper_get_type(), NULL);
61 xml_data->doc = doc;
63 return xml_data;
66 /* Return the first child of the root node with this name */
67 xmlNode *xml_get_section(XMLwrapper *xml, const gchar *ns, const gchar *name)
69 g_return_val_if_fail(xml != NULL, NULL);
70 g_return_val_if_fail(xml->doc != NULL, NULL);
72 return get_subnode(xmlDocGetRootElement(xml->doc), ns, name);
75 /* Return the (first) child of this node with the given name.
76 * NULL if not found.
77 * If there are several consecutive nodes with the same name but different
78 * xml:lang attributes, then the one matching the current locale is used,
79 * or the first one if none match.
81 xmlNode *get_subnode(xmlNode *node, const char *namespaceURI, const char *name)
83 for (node = node->xmlChildrenNode; node; node = node->next)
85 if (node->type != XML_ELEMENT_NODE)
86 continue;
88 if (strcmp(node->name, name))
89 continue;
91 if (node->ns == NULL || namespaceURI == NULL)
93 if (node->ns == NULL && namespaceURI == NULL)
94 return best_lang(node);
95 continue;
98 if (strcmp(node->ns->href, namespaceURI) == 0)
99 return best_lang(node);
102 return NULL;
105 /****************************************************************
106 * INTERNAL FUNCTIONS *
107 ****************************************************************/
109 /* Taking this node and each directly following node with the same name,
110 * return the one which matches the current LANG.
111 * Return the node itself if nothing matches.
113 static xmlNode *best_lang(xmlNode *first)
115 xmlNode *node = first;
116 const char *target_lang = current_lang ? current_lang : "en";
118 g_return_val_if_fail(first != NULL, NULL);
120 for (node = first->next; node; node = node->next)
122 char *lang;
124 if (node->type != XML_ELEMENT_NODE)
125 continue;
127 /* Check names match... */
128 if (strcmp(node->name, first->name))
129 return first;
131 /* Check namespaces match... */
132 if ((node->ns == NULL) != (first->ns == NULL))
133 return first;
135 if (node->ns && first->ns)
136 if (strcmp(node->ns->href, first->ns->href))
137 return first;
139 lang = xmlNodeGetLang(node);
141 if (!lang)
142 continue;
143 if (strcmp(lang, target_lang) == 0)
145 g_free(lang);
146 return node;
148 g_free(lang);
151 return first;
154 static void xml_wrapper_finialize(GObject *object)
156 XMLwrapper *xml = (XMLwrapper *) object;
158 if (xml->doc)
160 xmlFreeDoc(xml->doc);
161 xml->doc = NULL;
164 G_OBJECT_CLASS(parent_class)->finalize(object);
167 static void xml_wrapper_class_init(gpointer gclass, gpointer data)
169 GObjectClass *object = (GObjectClass *) gclass;
171 parent_class = g_type_class_peek_parent(gclass);
173 object->finalize = xml_wrapper_finialize;
176 static void xml_wrapper_init(GTypeInstance *object, gpointer gclass)
178 XMLwrapper *wrapper = (XMLwrapper *) object;
180 wrapper->doc = NULL;
183 static GType xml_wrapper_get_type(void)
185 static GType type = 0;
187 if (!type)
189 static const GTypeInfo info =
191 sizeof (XMLwrapperClass),
192 NULL, /* base_init */
193 NULL, /* base_finalise */
194 xml_wrapper_class_init,
195 NULL, /* class_finalise */
196 NULL, /* class_data */
197 sizeof(XMLwrapper),
198 0, /* n_preallocs */
199 xml_wrapper_init
202 type = g_type_register_static(G_TYPE_OBJECT, "XMLwrapper",
203 &info, 0);
206 return type;