RDF Literals with Prefixes


I am trying to construct RDF facts from other data and I wonder how the lovely prefix syntax is actually supposed to be used in what I am trying to do. (Use case in question: Sparql import. Have a general predicate that queries a Sparql server and gets a row(..., ...) back, pass this row(..., ...) to an auxiliary predicate which converts it into one or more rdf(..., ..., ...)s. The main predicate then asserts these.)

Consider the following tests. These are just five different tries to assert a fact like rdf(test:whatever, rdf:instance, test:concept), where the actual rdf objects are constructed in an auxiliary predicate (except for test1).

:- use_module(library(semweb/rdf11)).

:- rdf_register_prefix(test, 'http://testing/').

make_relation(X, rdf(test:X, rdf:instance, test:concept)).

make_relation_test4(X, rdf(X1, rdf:instance, Y1)) :-
    rdf_canonical_literal(test:X, X1),
    rdf_canonical_literal(test:concept, Y1).

make_relation_test5(X, rdf(X1, rdf:instance, Y1)) :-
    rdf_current_prefix(test, Test),
    atom_concat(Test, X, X1),
    atom_concat(Test, concept, Y1).

% works, but doesn't meet the goal
test1 :-
    rdf_assert(test:nothing, rdf:instance, test:concept).

% Type error: `rdf_object' expected, found `test:perhaps' (a compound)
% because 'O' is of the form 'test:concept', which is only allowed in 
% term_expansion (?).
test2 :-
    make_relation(everything, rdf(S, P, O)),
    rdf_assert(S, P, O).

% Same error when the part behind the prefix is a var.
test3 :-
    make_relation(whatever, rdf(S, P, test:O)),
    rdf_assert(S, P, test:O).

% Perhaps resolve the literal already in 'make_relation'? Nope, same error,
% but this time it is thrown by 'rdf_canonical_literal'.
test4 :-
    make_relation_test4(perhaps, rdf(S, P, O)),
    rdf_assert(S, P, O).

% Last resort: use 'rdf_current_prefix' and 'atom_concat'. This works!
% But it seems to be rather inelegant as it avoid using the facilities of the
% rdf library.
test5 :-
    make_relation_test5(working, rdf(S, P, O)),
    rdf_assert(S, P, O).

I have found querying to be similarly restricted, e.g. you can’t query like rdf(X, Y, test:concept), but perhaps this is unnecessary. But in the former case, how would you go about it? Is there any rule of thumb about how and when to construct these literals or am I just trying to do something stupid?

The prefix notation is handled at compile time as you discovered. If that doesn’t work you need to perform runtime expansion using rdf_global_id/2. Note that for compile time expansion to work with predicates you define yourself and that take RDF resources as arguments you need to declare this using rdf_meta/1.

Thank Jan,

that helps greatly!

It works like this, is this how you meant it?

% works
test6 :-
    make_relation(working, rdf(S, P, O)),
    rdf_global_id(S, S1),
    rdf_global_id(P, P1),
    rdf_global_id(O, O1),
    rdf_assert(S1, P1, O1).

:- rdf_meta(make_relation_meta(+, o, o, o)).
make_relation_meta(X, test:X, rdf:instance, test:concept).

% works, too
test7 :-
    make_relation_meta(meta, S, P, O),
    rdf_assert(S, P, O).