RDF Terms

The Term trait defines how you interact with RDF terms in Sophia.

Using terms

The first thing you usually need to know about a term is its kind (IRI, Literal...). The kind is described by the TermKind enum, and available from the Term::kind method.

use sophia::api::term::{SimpleTerm, Term, TermKind};
use TermKind::*;
let some_term: SimpleTerm = "foo".into_term();
match some_term.kind() {
    Iri => { /* ... */ }
    Literal => { /* ... */ }
    BlankNode => { /* ... */ }
    _ => { /* ... */ }
}

Alternatively, when only one kind is of interest, you can use Term::is_iri, Term::is_literal, Term::is_blank_node, etc.

If you are interested in the "value" of the term, the trait provides the following methods. All of them return an Option, which will be None if the term does not have the corresponding kind.

Finally, the method Term::eq can be used to check whether two values implementing Term represent the same RDF term. Note that the == operator may give a different result than Term::eq on some types implementing the Term trait.

Useful types implementing Term

Below is a list of useful types implementing the Term trait:

  • Iri<T> and IriRef<T>, where T: Borrow<str>, representing IRIs
  • BnodeId<T>, where T: Borrow<str>, representing blank nodes
  • str, representing literals of type xsd:string,
  • i32, isize and usize representing literals of type xsd:integer,
  • f64 representing literals of type xsd:double,
  • SimpleTerm(see below).

SimpleTerm is a straightforward implementation of Term, that can represent any kind of term, and can either own its own underlying data or borrow it from something else.

Any term can be converted to a SimpleTerm using the Term::as_simple method. This method borrows as much as possible from the initial term to avoid spurious memory allocation. Alternatively, to convert any term to a self-sufficient SimpleTerm, you can use Term::into_term

See also the list of recipes below.

Borrowing terms with Term::borrow_term

In Sophia, all functions accepting terms as parameters are expecting a type T: Term -- not &T, but the type T itself. So what happens when you want to call such a function with a term t, but still want to retain ownership of t?

The solution is to pass t.borrow_term() to the function. This method returns something implementing Term, representing the same RDF term as t, without waiving ownership. This is a very common pattern in Sophia.

More precisely, the type returned by t.borrow_term() is the associated type Term::BorrowTerm. In most cases, this is a reference or a copy of t.

Recipes for constructing terms

Constructing IRIs

fn main() -> Result<(), Box<dyn std::error::Error>> {

use sophia::{iri::IriRef, api::ns::Namespace};
let some_text = "http://example.org";
// construct an IRI from a constant
let iri1 = IriRef::new_unchecked("http://example.org");

// construct an IRI from an untrusted string
let iri2 = IriRef::new(some_text)?;

// construct multiple IRIs from a namespace
let ns = Namespace::new_unchecked("http://example.org/ns#");
let iri3 = ns.get_unchecked("foo");
let iri4 = ns.get(some_text)?;

// standard namespaces
use sophia::api::ns::{rdf, xsd};
let iri5 = rdf::Property ;
let iri6 = xsd::string ;

Ok(()) }

Constructing literals

fn main() -> Result<(), Box<dyn std::error::Error>> {

use sophia::api::{ns::xsd, term::{LanguageTag, SimpleTerm, Term}};
// use native types for xsd::string, xsd::integer, xsd::double
let lit_string = "hello world";
let lit_integer = 42;
let lit_double = 1.23;

// construct a language-tagged string
let fr = LanguageTag::new_unchecked("fr");
let lit_fr = "Bonjour le monde" * fr;

// construct a literal with an arbitrary datatype
let lit_date = "2023-11-15" * xsd::date;

Ok(()) }

Constructing blank nodes

fn main() -> Result<(), Box<dyn std::error::Error>> {

use sophia::api::term::BnodeId;
let b = BnodeId::new_unchecked("x");

Ok(()) }

Converting terms into a different type

use sophia::api::{ns::xsd, term::{SimpleTerm, Term}};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let some_term = "42" * xsd::integer;
let t1: SimpleTerm = "hello".into_term();
let t2: i32 = some_term.try_into_term()?;
Ok(()) }

1

Note that in Sophia's generalized RDF model, IRIs can be relative IRI reference.

2

Note that this kind only exist in Sophia's generalized RDF model.