commit 45ff5c082646e750abfa994d9c1e9e5d4072fb66
parent 3ce805ad5be37ecd6151b42ae123170237d6740d
Author: Dan Callaghan <djc@djc.id.au>
Date: Sun, 28 Oct 2012 18:37:41 +1000
custom mappings for RDF types to GValues
Diffstat:
5 files changed, 103 insertions(+), 36 deletions(-)
diff --git a/glibrdf.c b/glibrdf.c
@@ -47,8 +47,48 @@ static GDateTime *parse_iso8601_datetime(const gchar *s) {
}
// XXX handle parse failures more gracefully?
-// XXX should have some kind of registry so that callers can add new types
-void librdf_node_get_literal_gvalue(librdf_node *node, GValue *value_out) {
+
+static void integer(const gchar *lv, GValue *value_out) {
+ g_value_init(value_out, G_TYPE_INT64);
+ gchar *lv_unconsumed;
+ g_value_set_int64(value_out, g_ascii_strtoll(lv, &lv_unconsumed, 10));
+ g_return_if_fail(*lv_unconsumed == '\0');
+ return;
+}
+
+static void date(const gchar *lv, GValue *value_out) {
+ GDate *date = parse_iso8601_date(lv);
+ g_return_if_fail(date != NULL);
+ g_value_init(value_out, G_TYPE_DATE);
+ g_value_set_boxed(value_out, date);
+ return;
+}
+
+static void datetime(const gchar *lv, GValue *value_out) {
+ GDateTime *datetime = parse_iso8601_datetime(lv);
+ g_return_if_fail(datetime != NULL);
+ g_value_init(value_out, G_TYPE_DATE_TIME);
+ g_value_set_boxed(value_out, datetime);
+ return;
+}
+
+librdf_gvalue_adaptor_func librdf_default_gvalue_adaptor_map(librdf_uri *datatype_uri) {
+ const gchar *datatype_uri_string =
+ (const gchar *)librdf_uri_as_string(datatype_uri);
+ if (g_strcmp0(datatype_uri_string,
+ "http://www.w3.org/2001/XMLSchema#integer") == 0)
+ return integer;
+ if (g_strcmp0(datatype_uri_string,
+ "http://www.w3.org/TR/xmlschema-2/#date") == 0)
+ return date;
+ if (g_strcmp0(datatype_uri_string,
+ "http://www.w3.org/TR/xmlschema-2/#datetime") == 0)
+ return datetime;
+ return NULL;
+}
+
+void librdf_node_get_literal_gvalue(librdf_node *node,
+ librdf_gvalue_adaptor_map_func adaptor_map, GValue *value_out) {
g_return_if_fail(librdf_node_is_literal(node));
const gchar *lv = (const gchar *)librdf_node_get_literal_value(node);
g_return_if_fail(lv != NULL);
@@ -58,33 +98,15 @@ void librdf_node_get_literal_gvalue(librdf_node *node, GValue *value_out) {
g_value_set_string(value_out, lv);
return;
}
- const gchar *datatype_uri_string =
- (const gchar *)librdf_uri_as_string(datatype_uri);
- if (g_strcmp0(datatype_uri_string,
- "http://www.w3.org/2001/XMLSchema#integer") == 0) {
- g_value_init(value_out, G_TYPE_INT64);
- gchar *lv_unconsumed;
- g_value_set_int64(value_out, g_ascii_strtoll(lv, &lv_unconsumed, 10));
- g_return_if_fail(*lv_unconsumed == '\0');
- return;
- }
- if (g_strcmp0(datatype_uri_string,
- "http://www.w3.org/TR/xmlschema-2/#date") == 0) {
- GDate *date = parse_iso8601_date(lv);
- g_return_if_fail(date != NULL);
- g_value_init(value_out, G_TYPE_DATE);
- g_value_set_boxed(value_out, date);
- return;
- }
- if (g_strcmp0(datatype_uri_string,
- "http://www.w3.org/TR/xmlschema-2/#datetime") == 0) {
- GDateTime *datetime = parse_iso8601_datetime(lv);
- g_return_if_fail(datetime != NULL);
- g_value_init(value_out, G_TYPE_DATE_TIME);
- g_value_set_boxed(value_out, datetime);
- return;
+ if (adaptor_map == NULL)
+ adaptor_map = librdf_default_gvalue_adaptor_map;
+ librdf_gvalue_adaptor_func adaptor = adaptor_map(datatype_uri);
+ if (adaptor == NULL) {
+ g_warning("Unhandled RDF type %s", librdf_uri_as_string(datatype_uri));
+ g_value_init(value_out, G_TYPE_STRING);
+ g_value_set_string(value_out, lv);
}
- g_warning("Unhandled RDF type %s", librdf_uri_as_string(datatype_uri));
- g_value_init(value_out, G_TYPE_STRING);
- g_value_set_string(value_out, lv);
+ adaptor(lv, value_out);
+ g_return_if_fail(G_IS_VALUE(value_out));
+ return;
}
diff --git a/glibrdf.h b/glibrdf.h
@@ -13,6 +13,11 @@
GType librdf_node_get_gtype(void);
#define G_TYPE_RDF_NODE librdf_node_get_gtype()
-void librdf_node_get_literal_gvalue(librdf_node *node, GValue *value_out);
+typedef void (*librdf_gvalue_adaptor_func)(const gchar *lv, GValue *value_out);
+typedef librdf_gvalue_adaptor_func (*librdf_gvalue_adaptor_map_func)(librdf_uri *datatype_uri);
+librdf_gvalue_adaptor_func librdf_default_gvalue_adaptor_map(librdf_uri *datatype_uri);
+void librdf_node_get_literal_gvalue(librdf_node *node,
+ librdf_gvalue_adaptor_map_func adaptor_map,
+ GValue *value_out);
#endif
diff --git a/glibrdf.vapi b/glibrdf.vapi
@@ -397,6 +397,13 @@ namespace Rdf {
LAST
}
+ [CCode (cname = "librdf_gvalue_adaptor_func", has_target = false)]
+ public delegate GLib.Value GValueAdaptor(string lv);
+ [CCode (cname = "librdf_gvalue_adaptor_map_func", has_target = false)]
+ public delegate GValueAdaptor GValueAdaptorMap(Uri datatype_uri);
+ [CCode (cname = "librdf_default_gvalue_adaptor_map")]
+ public GValueAdaptor default_gvalue_adaptor_map(Uri datatype_uri);
+
[Compact]
[Immutable]
[CCode (cname = "librdf_node",
@@ -450,7 +457,7 @@ namespace Rdf {
[CCode (cname = "librdf_node_get_literal_value_datatype_uri")]
public unowned Uri? get_literal_value_datatype_uri ();
[CCode (cname = "librdf_node_get_literal_gvalue")]
- public GLib.Value get_literal_gvalue();
+ public GLib.Value get_literal_gvalue(GValueAdaptorMap? adaptor_map = null);
[CCode (cname = "librdf_node_get_li_ordinal")]
public int get_li_ordinal ();
diff --git a/test-data.xml b/test-data.xml
@@ -6,5 +6,6 @@
<ex:integer rdf:datatype="http://www.w3.org/2001/XMLSchema#integer">123</ex:integer>
<ex:date rdf:datatype="http://www.w3.org/TR/xmlschema-2/#date">1986-08-16</ex:date>
<ex:datetime rdf:datatype="http://www.w3.org/TR/xmlschema-2/#datetime">2012-07-22T15:57:41+10:00</ex:datetime>
+ <ex:custom rdf:datatype="http://example.com/customType">asdf</ex:custom>
</rdf:Description>
</rdf:RDF>
diff --git a/test_literal_gvalue.c b/test_literal_gvalue.c
@@ -59,7 +59,7 @@ static void test_untyped(FIXTURE_TYPE *fixture, DATA) {
librdf_node *obj = librdf_model_get_target(fixture->model, subj, prop);
g_assert(obj != NULL);
GValue value = {0};
- librdf_node_get_literal_gvalue(obj, &value);
+ librdf_node_get_literal_gvalue(obj, NULL, &value);
g_assert(G_VALUE_HOLDS(&value, G_TYPE_STRING));
g_assert_cmpstr(g_value_get_string(&value), ==, "blah");
g_value_unset(&value);
@@ -78,7 +78,7 @@ static void test_integer(FIXTURE_TYPE *fixture, DATA) {
librdf_node *obj = librdf_model_get_target(fixture->model, subj, prop);
g_assert(obj != NULL);
GValue value = {0};
- librdf_node_get_literal_gvalue(obj, &value);
+ librdf_node_get_literal_gvalue(obj, NULL, &value);
g_assert(G_VALUE_HOLDS(&value, G_TYPE_INT64));
g_assert_cmpint(g_value_get_int64(&value), ==, 123);
g_value_unset(&value);
@@ -97,7 +97,7 @@ static void test_date(FIXTURE_TYPE *fixture, DATA) {
librdf_node *obj = librdf_model_get_target(fixture->model, subj, prop);
g_assert(obj != NULL);
GValue value = {0};
- librdf_node_get_literal_gvalue(obj, &value);
+ librdf_node_get_literal_gvalue(obj, NULL, &value);
g_assert(G_VALUE_HOLDS(&value, G_TYPE_DATE));
GDate *date = (GDate *)g_value_get_boxed(&value);
g_assert_cmpuint(g_date_get_year(date), ==, 1986);
@@ -119,7 +119,7 @@ static void test_datetime(FIXTURE_TYPE *fixture, DATA) {
librdf_node *obj = librdf_model_get_target(fixture->model, subj, prop);
g_assert(obj != NULL);
GValue value = {0};
- librdf_node_get_literal_gvalue(obj, &value);
+ librdf_node_get_literal_gvalue(obj, NULL, &value);
g_assert(G_VALUE_HOLDS(&value, G_TYPE_DATE_TIME));
GDateTime *datetime = (GDateTime *)g_value_get_boxed(&value);
g_assert_cmpint(g_date_time_get_year(datetime), ==, 2012);
@@ -136,9 +136,41 @@ static void test_datetime(FIXTURE_TYPE *fixture, DATA) {
librdf_free_node(subj);
}
+static void custom_adaptor(const gchar *lv, GValue *value_out) {
+ g_value_init(value_out, G_TYPE_STRING);
+ g_value_set_static_string(value_out, "custom");
+ return;
+}
+static librdf_gvalue_adaptor_func custom_adaptor_map(librdf_uri *datatype_uri) {
+ const gchar *datatype_uri_string =
+ (const gchar *)librdf_uri_as_string(datatype_uri);
+ if (g_strcmp0(datatype_uri_string, "http://example.com/customType") == 0)
+ return custom_adaptor;
+ return librdf_default_gvalue_adaptor_map(datatype_uri);
+}
+static void test_custom_adaptor(FIXTURE_TYPE *fixture, DATA) {
+ librdf_node *subj = librdf_new_node_from_uri_string(fixture->world,
+ (const unsigned char *)"http://example.com/Resource");
+ g_assert(subj != NULL);
+ librdf_node *prop = librdf_new_node_from_uri_string(fixture->world,
+ (const unsigned char *)"http://example.com/custom");
+ g_assert(prop != NULL);
+ librdf_node *obj = librdf_model_get_target(fixture->model, subj, prop);
+ g_assert(obj != NULL);
+ GValue value = {0};
+ librdf_node_get_literal_gvalue(obj, custom_adaptor_map, &value);
+ g_assert(G_VALUE_HOLDS(&value, G_TYPE_STRING));
+ g_assert_cmpstr(g_value_get_string(&value), ==, "custom");
+ g_value_unset(&value);
+ librdf_free_node(obj);
+ librdf_free_node(prop);
+ librdf_free_node(subj);
+}
+
void add_literal_gvalue_tests(void) {
TEST_ADD(test_untyped);
TEST_ADD(test_integer);
TEST_ADD(test_date);
TEST_ADD(test_datetime);
+ TEST_ADD(test_custom_adaptor);
}