const char *osync_xmlfield_get_key_value(OSyncXMLField *xmlfield, const char *key)
{
  xmlNodePtr cur = NULL;
  osync_assert(xmlfield);
  osync_assert(key);
	
  cur = xmlfield->node->children;
  for(; cur != NULL; cur = cur->next) {
    if(!xmlStrcmp(cur->name, BAD_CAST key))
      return (const char *)osync_xml_node_get_content(cur);
    //				return (const char *)cur->children->content;
    //				return (const char *)xmlNodeGetContent(cur);
  }
  return NULL;
}
const char *osync_xmlfield_get_nth_key_value(OSyncXMLField *xmlfield, int nth)
{
  int count;
  xmlNodePtr child = NULL;

  osync_assert(xmlfield);
	
  child = xmlfield->node->children;
	
  for(count=0; child != NULL; count++) {
    if(count == nth)
      return (const char *)osync_xml_node_get_content(child);
    //			return (const char *)child->children->content;
    //			return (const char *)xmlNodeGetContent(child);
    child = child->next;
  }
  return NULL;
}
OSyncList *osync_version_load_from_descriptions(OSyncError **error, const char *descriptiondir, const char *schemadir)
{
	GDir *dir = NULL;
	GError *gerror = NULL;
	const char *descpath = descriptiondir ? descriptiondir : OPENSYNC_DESCRIPTIONSDIR; 
	const char *schemapath = schemadir ? schemadir : OPENSYNC_SCHEMASDIR; 
	char *filename = NULL;
	const gchar *de = NULL;
	OSyncList *versions = NULL;
	OSyncVersion *version = NULL;
	xmlDocPtr doc;
	xmlNodePtr root;
	xmlNodePtr cur;
	xmlNodePtr child;
	
	osync_trace(TRACE_ENTRY, "%s(%p)", __func__, error);
	
	dir = g_dir_open(descpath, 0, &gerror);
	if (!dir) {
		/* If description directory doesn't exist (e.g. unittests), just ignore this. */
		osync_trace(TRACE_EXIT, "Unable to open directory %s: %s", descpath, gerror->message);
		g_error_free(gerror);
		return NULL;
	}
	
	while ((de = g_dir_read_name(dir))) {
		char *schemafilepath = NULL;
		osync_bool res;

		filename = osync_strdup_printf ("%s%c%s", descpath, G_DIR_SEPARATOR, de);
		
		if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR) || !g_pattern_match_simple("*.xml", filename)) {
			osync_free(filename);
			continue;
		}
		
		doc = xmlReadFile(filename, NULL, XML_PARSE_NOBLANKS);
		if(!doc) {
			osync_free(filename);
			continue;
		}
		
		osync_free(filename);
		
		root = xmlDocGetRootElement(doc);
		if(!root || !xmlStrEqual(root->name, BAD_CAST "versions")) {
			osync_xml_free_doc(doc);
			continue;
		}

		schemafilepath = osync_strdup_printf("%s%c%s", schemapath, G_DIR_SEPARATOR, "descriptions.xsd");
		res = osync_xml_validate_document(doc, schemafilepath);
		osync_free(schemafilepath);

		if(res == FALSE) {
			osync_xml_free_doc(doc);
			continue;
		}
		
		cur = root->children;
		for(; cur != NULL; cur = cur->next) {
		
			version = osync_version_new(error);
			if(!version) {
				OSyncList *cur = NULL;
				osync_xml_free_doc(doc);
				cur = osync_list_first(versions);
				while(cur) {
					osync_version_unref(cur->data);
					cur = cur->next;	
				}
				goto error;
			}
				
			child = cur->children;
			osync_version_set_plugin(version, (const char *)osync_xml_node_get_content(child));
			child = child->next;
			osync_version_set_priority(version, (const char *)osync_xml_node_get_content(child));
			child = child->next;
			osync_version_set_vendor(version, (const char *)osync_xml_node_get_content(child));
			child = child->next;
			osync_version_set_modelversion(version, (const char *)osync_xml_node_get_content(child));
			child = child->next;
			osync_version_set_firmwareversion(version, (const char *)osync_xml_node_get_content(child));
			child = child->next;
			osync_version_set_softwareversion(version, (const char *)osync_xml_node_get_content(child));
			child = child->next;
			osync_version_set_hardwareversion(version, (const char *)osync_xml_node_get_content(child));
			child = child->next;
			osync_version_set_identifier(version, (const char *)osync_xml_node_get_content(child));
			
			versions = osync_list_append(versions, version);
		}
		
		osync_xml_free_doc(doc);
	}
	
	g_dir_close(dir);
	
	osync_trace(TRACE_EXIT, "%s: %p", __func__, versions);
	return versions;

 error:
	osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
	return NULL;
}
const char *osync_xmlfield_get_value(OSyncXMLField *xmlfield)
{
	osync_return_val_if_fail(xmlfield, "");
	return (const char *)osync_xml_node_get_content(xmlfield->node);
}