1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2001-2003 Ximian, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU Lesser General Public
7 * License as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
26 #include <libxml/entities.h>
27 #include <libxml/tree.h>
28 #include <libxml/xmlmemory.h>
31 #include <glib/gstdio.h>
33 #include "e-xml-hash-utils.h"
34 #include "e-xml-utils.h"
38 * @doc: The #xmlDoc to store in a hash table.
39 * @type: The value type to use as a key in the hash table.
41 * Creates a #GHashTable representation of the #xmlDoc @doc.
42 * If @type is * @E_XML_HASH_TYPE_PROPERTY, all XML nodes will be
43 * indexed in the #GHashTable by name. If @type is
44 * %E_XML_HASH_TYPE_OBJECT_UID, then XML objects will be indexed in
45 * the hash by their UID (other nodes will still be indexed by name).
47 * Returns: The newly-created #GHashTable representation of @doc.
50 e_xml_to_hash (xmlDoc *doc, EXmlHashType type)
56 hash = g_hash_table_new (g_str_hash, g_str_equal);
58 root = xmlDocGetRootElement (doc);
59 for (node = root->xmlChildrenNode; node; node = node->next) {
60 if (node->name == NULL || node->type != XML_ELEMENT_NODE)
63 if (type == E_XML_HASH_TYPE_OBJECT_UID &&
64 !strcmp ((char*)node->name, "object"))
65 key = xmlGetProp (node, (xmlChar*)"uid");
67 key = xmlStrdup (node->name);
70 g_warning ("Key not found!!");
74 value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
77 g_warning ("Found a key with no value!!");
81 g_hash_table_insert (hash, g_strdup ((char*)key), g_strdup ((char*)value));
97 foreach_save_func (gpointer key, gpointer value, gpointer user_data)
99 struct save_data *sd = user_data;
103 if (sd->type == E_XML_HASH_TYPE_OBJECT_UID) {
104 new_node = xmlNewNode (NULL, (xmlChar*)"object");
105 xmlNewProp (new_node, (xmlChar*)"uid", (const xmlChar *) key);
107 new_node = xmlNewNode (NULL, (const xmlChar *) key);
109 enc = xmlEncodeEntitiesReentrant (sd->doc, value);
110 xmlNodeSetContent (new_node, enc);
113 xmlAddChild (sd->root, new_node);
118 * @hash: The #GHashTable to extract the XML from.
119 * @type: The #EXmlHashType used to store the XML.
120 * @root_name: The name to call the new #xmlDoc.
122 * Uses the key/value pair representation of an XML structure in @hash
123 * to build an equivalent #xmlDoc. This is the reverse of
126 * Returns: The #xmlDoc created from the data in @hash.
129 e_xml_from_hash (GHashTable *hash, EXmlHashType type, const char *root_name)
134 doc = xmlNewDoc ((xmlChar*)"1.0");
135 doc->encoding = xmlStrdup ((xmlChar*)"UTF-8");
138 sd.root = xmlNewDocNode (doc, NULL, (xmlChar*)root_name, NULL);
139 xmlDocSetRootElement (doc, sd.root);
141 g_hash_table_foreach (hash, foreach_save_func, &sd);
146 free_values (gpointer key, gpointer value, gpointer data)
153 * e_xml_destroy_hash:
154 * @hash: The #GHashTable to destroy.
156 * Frees the memory used by @hash and its contents.
159 e_xml_destroy_hash (GHashTable *hash)
161 g_hash_table_foreach (hash, free_values, NULL);
162 g_hash_table_destroy (hash);
169 * A hash table representation of an XML file.
178 * @filename: The name of an XML file.
180 * Creates a new #EXmlHash from the file @filename. If @filename does
181 * not already exist, an empty #EXmlHash will be created.
183 * Returns: The new #EXmlHash structure, or %NULL if unable to parse
187 e_xmlhash_new (const char *filename)
192 g_return_val_if_fail (filename != NULL, NULL);
194 hash = g_new0 (EXmlHash, 1);
195 hash->filename = g_strdup (filename);
197 if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
198 doc = e_xml_parse_file (filename);
200 e_xmlhash_destroy (hash);
204 hash->objects = e_xml_to_hash (doc, E_XML_HASH_TYPE_OBJECT_UID);
207 hash->objects = g_hash_table_new (g_str_hash, g_str_equal);
215 * @hash: The #EXmlHash to add an entry to.
216 * @key: The key to use for the entry.
217 * @data: The value of the new entry.
219 * Adds a new key/value pair to the #EXmlHash @hash.
222 e_xmlhash_add (EXmlHash *hash, const char *key, const char *data)
224 g_return_if_fail (hash != NULL);
225 g_return_if_fail (key != NULL);
226 g_return_if_fail (data != NULL);
228 e_xmlhash_remove (hash, key);
229 g_hash_table_insert (hash->objects, g_strdup (key), g_strdup (data));
234 * @hash: The #EXmlHash to remove an entry from.
235 * @key: The key of the entry to remove.
237 * Remove the entry in @hash with key equal to @key, if it exists.
240 e_xmlhash_remove (EXmlHash *hash, const char *key)
245 g_return_if_fail (hash != NULL);
246 g_return_if_fail (key != NULL);
248 if (g_hash_table_lookup_extended (hash->objects, key, &orig_key, &orig_value)) {
249 g_hash_table_remove (hash->objects, key);
257 * @hash: The #EXmlHash to compare against.
258 * @key: The key of the hash entry to compare with.
259 * @compare_data: The data to compare against the hash entry.
261 * Compares the value with key equal to @key in @hash against
264 * Returns: E_XMLHASH_STATUS_SAME if the value and @compare_data are
265 * equal,E_XMLHASH_STATUS_DIFFERENT if they are different, or
266 * E_XMLHASH_STATUS_NOT_FOUND if there is no entry in @hash with
267 * its key equal to @key.
270 e_xmlhash_compare (EXmlHash *hash, const char *key, const char *compare_data)
275 g_return_val_if_fail (hash != NULL, E_XMLHASH_STATUS_NOT_FOUND);
276 g_return_val_if_fail (key != NULL, E_XMLHASH_STATUS_NOT_FOUND);
277 g_return_val_if_fail (compare_data != NULL, E_XMLHASH_STATUS_NOT_FOUND);
279 data = g_hash_table_lookup (hash->objects, key);
281 return E_XMLHASH_STATUS_NOT_FOUND;
283 rc = strcmp (data, compare_data);
285 return E_XMLHASH_STATUS_SAME;
287 return E_XMLHASH_STATUS_DIFFERENT;
296 foreach_hash_func (gpointer key, gpointer value, gpointer user_data)
298 foreach_data_t *data = (foreach_data_t *) user_data;
300 data->func ((const char *) key, (const char *) value, data->user_data);
304 * e_xmlhash_foreach_key:
305 * @hash: An #EXmlHash.
306 * @func: The #EXmlHashFunc to execute on the data in @hash.
307 * @user_data: The data to pass to @func.
309 * Executes @func against each key/value pair in @hash.
312 e_xmlhash_foreach_key (EXmlHash *hash, EXmlHashFunc func, gpointer user_data)
316 g_return_if_fail (hash != NULL);
317 g_return_if_fail (func != NULL);
320 data.user_data = user_data;
321 g_hash_table_foreach (hash->objects, foreach_hash_func, &data);
325 e_xmlhash_foreach_key_remove (EXmlHash *hash, EXmlHashRemoveFunc func, gpointer user_data)
327 g_return_if_fail (hash != NULL);
328 g_return_if_fail (func != NULL);
330 g_hash_table_foreach_remove (hash->objects, (GHRFunc)func, user_data);
335 * @hash: The #EXmlHash to write.
337 * Writes the XML represented by @hash to the file originally passed
338 * to e_xmlhash_new().
341 e_xmlhash_write (EXmlHash *hash)
345 g_return_if_fail (hash != NULL);
347 doc = e_xml_from_hash (hash->objects, E_XML_HASH_TYPE_OBJECT_UID, "xmlhash");
349 e_xml_save_file (hash->filename, doc);
356 * @hash: The #EXmlHash to destroy.
358 * Frees the memory associated with @hash.
361 e_xmlhash_destroy (EXmlHash *hash)
363 g_return_if_fail (hash != NULL);
365 g_free (hash->filename);
367 e_xml_destroy_hash (hash->objects);