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.
-
If the term is a blank node,
Term::bnode_idreturns its blank node identifier. -
If the term is a literal:
Term::lexical_formreturns its lexical form (the "textual value" of the literal),Term::datatypereturns its datatype IRI1,Term::language_tagreturns its language tag, if any.
-
If the term is a quoted triple:
Term::triplereturns its 3 components in an array of terms,Term::constituentsiterates over all its constituents,Term::atomsiterates over all its atomic (i.e. non quoted-triple) constituents.- (those three methods also have a
to_Xversion that destructs the original term instead of borrowing it)
-
If the term is a variable2,
Term::variablereturns its name.
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>andIriRef<T>, whereT: Borrow<str>, representing IRIsBnodeId<T>, whereT: Borrow<str>, representing blank nodesstr, representing literals of typexsd:string,i32,isizeandusizerepresenting literals of typexsd:integer,f64representing literals of typexsd: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::{BaseDirection, 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 directional language-tagged string
let he = LanguageTag::new_unchecked("he");
let lit_he = "ספרים בינלאומיים" * he * BaseDirection::Rtl;
// 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(()) }
-
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. ↩