This document is licensed under a Creative Commons Attribution 3.0 License.
In the Resource Description Framework, literals are composed of a UNICODE string (the lexical form), a datatype IRI, and optionally, when the datatype IRI is rdf:langString
, a language tag. Any IRI can take the place of a datatype IRI, but the specification only defines the precise meaning of a literal when the datatype IRI is among a predefined subset. Custom datatypes have reported use on the web of data, but their support by RDF processors is rare and implementation specific.
We propose a mechanism for a generic support of custom datatypes.
Following simple guidelines, (i) definitions of arbitrary custom datatypes may be published on the web, and (ii) a generic RDF processor or SPARQL query engine can discover datatypes on-the-fly, and perform operations uniformly.
This document provides:
This document is merely a public working draft of a potential specification. It has no official standing of any kind and does not represent the support or consensus of any standards organisation.
CustomDatatypeFactory
CustomDatatype
CustomDatatype
CustomDatatype
CustomDatatype
CustomDatatype
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words MUST and SHOULD are to be interpreted as described in [RFC2119].
Custom Datatypes MUST conform to these guidelines.
RDF processors and SPARQL query engines SHOULD take care of the code they process.
Recommendations for Custom Datatype Publishers are as follows.
aaa
to identify custom datatype Da.aaa
, let it retrieve a document that contains executable code.CustomDatatypeFactory
, an interface with a unique function getDatatype( iri )
, whose behaviour is described below.aaa
, function getDatatype( iri )
returns an object that implements interface CustomDatatype
described below.This API provides mechanisms that enable developers to process custom datatypes and custom literals uniformly.
CustomDatatypeFactory
Interface CustomDatatypeFactory
MUST implement the following methods.
[Constructor]
interface CustomDatatypeFactory {
CustomDatatype
getDatatype (String iri);
};
getDatatype
In the context of the code contained in a custom datatype specification file, i.e., an instance of interface CustomDatatypeFactory
, getDatatype(uri)
returns an instance of interface CustomDatatype
, or throws an exception.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
iri | String | ✘ | ✘ |
CustomDatatype
CustomDatatype
Interface CustomDatatype
MUST implement the following methods.
[Constructor]
interface CustomDatatype {
String getIri ();
Boolean isWellFormed (String lexicalForm);
Boolean recognisesDatatype (String datatypeIri);
String[] getRecognisedDatatypes ();
Boolean isEqual (String lexicalForm1, String lexicalForm2, optional String datatypeIri2);
Integer compare (String lexicalForm1, String lexicalForm2, optional String datatypeIri2);
String getNormalForm (String lexicalForm);
String importLiteral (String lexicalForm, String datatypeIri);
String exportLiteral (String lexicalForm, String datatypeIri);
};
compare
lexicalForm
and this datatype is lower, equal, or greater than the value of literal with lexical form lexicalForm2
and datatype identified by IRI datatypeIri2
.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
lexicalForm1 | String | ✘ | ✘ | |
lexicalForm2 | String | ✘ | ✘ | |
datatypeIri2 | String | ✘ | ✔ |
Integer
exportLiteral
datatypeIri
, with a value equal to that of a literal with lexical form lexicalForm
and this datatype.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
lexicalForm | String | ✘ | ✘ | |
datatypeIri | String | ✘ | ✘ |
String
getIri
String
getNormalForm
lexicalForm
and this datatype.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
lexicalForm | String | ✘ | ✘ |
String
getRecognisedDatatypes
String[]
importLiteral
lexicalForm
and datatype identified by datatypeIri
.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
lexicalForm | String | ✘ | ✘ | |
datatypeIri | String | ✘ | ✘ |
String
isEqual
lexicalForm1
and this datatype has the same value as literal with lexical form lexicalForm2
and datatype identified by IRI datatypeIri2
.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
lexicalForm1 | String | ✘ | ✘ | |
lexicalForm2 | String | ✘ | ✘ | |
datatypeIri2 | String | ✘ | ✔ |
Boolean
isWellFormed
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
lexicalForm | String | ✘ | ✘ |
Boolean
recognisesDatatype
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
datatypeIri | String | ✘ | ✘ |
Boolean
CustomDatatype
Let da
be the specification object of a custom datatype Da identified by IRI aaa
, i.e., an instance of interface CustomDatatype
returned by a call to method getDatatype(aaa)
. da
is intra-conformant if and only if all of the following is true
getIri
MUST be such that:
da.getIri()
returns a stringda.getIri() = aaa
isWellFormed
MUST be such that:
da.isWellFormed(sss)
returns a boolean if sss
is a string, and throws an exception otherwisegetNormalForm
MUST be such that:
da.getNormalForm(sss)
returns a string if da.isWellFormed(sss) = true
, and throws an exception otherwiseda.isWellFormed(sss) = true
, then da.isWellFormed( da.getNormalForm(sss) ) = true
da.isWellFormed(sss) = true
, then da.getNormalForm( da.getNormalForm(sss) ) = da.getNormalForm(sss)
recognisesDatatype
MUST be such that:
da.recognisesDatatype(bbb)
returns a boolean if bbb
is a string, and throws an exception otherwiseda.recognisesDatatype(aaa) = true
recognisedDatatypes
MUST be such that:
da.recognisedDatatypes()
is the set of strings bbb
such that da.recognisesDatatype(bbb) = true
importLiteral
MUST be such that:
da.recognisesDatatype(bbb) = true
and ttt
is a string, then da.importLiteral(ttt, bbb)
either returns a string, or throws an exception. Else, it throws an exception.da.importLiteral(ttt, bbb)
returns a string, then isWellFormed( da.importLiteral(ttt, bbb) ) = true
da.isWellFormed(sss) = true
, then da.importLiteral(sss, aaa)
returns a string, and da.getNormalForm(sss) = da.getNormalForm( da.importLiteral(sss, aaa) )
exportLiteral
MUST be such that:
da.recognisesDatatype(bbb) = true
and da.isWellFormed(sss) = true
, then da.exportLiteral(sss, bbb)
either returns a string, or throws an exception. Else, it throws an exception.da.exportLiteral(sss, bbb)
returns a string, then da.getNormalForm(sss) = da.getNormalForm( da.importLiteral( da.exportLiteral(sss, bbb), bbb) )
isEqual
MUST be such that:
da.isWellFormed(sss) = true
and da.importLiteral(ttt, bbb)
returns a string, then da.isEqual(sss, ttt, bbb)
returns a boolean. Else, it throws an exception.da.isWellFormed(sss) = true
and da.importLiteral(ttt, bbb)
returns a string, then da.isEqual(sss, uuu, ccc) = true
if and only if da.getNormalForm(sss) = da.getNormalForm( da.importLiteral(uuu, ccc) )
da.isWellFormed(sss) = true
and da.isWellFormed(ttt) = true
, then da.isEqual(sss, ttt) = da.isEqual(sss, ttt, aaa)
. Else, it throws an exception.da.isWellFormed(sss) = true
, da.isWellFormed(ttt) = true
, and da.isWellFormed(uuu) = true
, then:
da.isEqual(sss, ttt) = da.isEqual(ttt, sss)
da.isEqual(sss, ttt)
and da.isEqual(ttt, uuu)
, then da.isEqual(sss, uuu)
compare
MUST be such that:
da.isWellFormed(sss) = true
and da.importLiteral(ttt, bbb)
returns a string, then da.compare(sss, ttt, bbb)
returns an integer. Else, it throws an exception.da.isWellFormed(sss) = true
and da.importLiteral(ttt, bbb)
returns a string, then da.compare(sss, uuu, ccc) = 0
if and only if da.isEqual(sss, uuu, ccc) = true
da.isWellFormed(sss) = true
and da.isWellFormed(ttt) = true
, then da.compare(sss, ttt) = da.compare(sss, ttt, aaa)
. Else, it throws an exception.da.isWellFormed(sss) = true
, da.isWellFormed(ttt) = true
, and da.isWellFormed(uuu) = true
, then:
da.compare(sss, ttt)
and da.compare(ttt, sss)
have opposite signsda.compare(sss, ttt) ≤ 0
and da.compare(ttt, uuu) ≤ 0
, then da.compare(sss, uuu) ≤ 0
CustomDatatype
Let da
be the specification object of a custom datatype Da identified by IRI aaa
. da
is extra-conformant if and only if, for every bbb
in da.getRecognisedDatatypes()
, all of the following is true.
importLiteral
MUST be such that:
db.isWellFormed(ttt) = false
, then da.importLiteral(ttt, bbb)
throws an exception.exportLiteral
MUST be such that:
da.exportLiteral(sss, bbb)
returns a string, then db.isWellFormed( da.exportLiteral(sss, bbb) )
.isEqual
MUST be such that:
da.isEqual(sss, ttt, bbb) = true
and db.isEqual(ttt, uuu, ccc) = true
, then da.isEqual(sss, ttt, bbb) = true
compare
MUST be such that:
da.compare(sss, ttt, bbb) ≤ 0
and db.compare(ttt, uuu, ccc) ≤ 0
, then da.compare(sss, ttt, bbb) ≤ 0
da.compare(sss, ttt, bbb) ≥ 0
and db.compare(ttt, uuu, ccc) ≥ 0
, then da.compare(sss, ttt, bbb) ≥ 0
CustomDatatype
Let da
be the specification object of a custom datatype Da identified by IRI aaa
. da
is inter-conformant if and only if, for every bbb
in da.getRecognisedDatatypes()
such that one may retrieve a specification object db
of the custom datatype Db identified by IRI bbb
, then db
is conformant, and all of the following is true.
importLiteral
MUST be such that:
da.importLiteral(ttt, bbb)
returns a string if and only if db.exportLiteral(ttt, aaa)
returns a stringisEqual
MUST be such that:
da.isEqual(sss, ttt, bbb) = true
if and only if db.isEqual(ttt, sss, aaa) = true
compare
MUST be such that:
da.importLiteral(sss, bbb)
and db.exportLiteral(sss, aaa)
returns a string, then da.compare(sss, ttt, bbb)
and db.compare(ttt, sss, aaa)
have opposite signsCustomDatatype
Let da
be the specification object of a custom datatype Da identified by IRI aaa
. da
is conformant if and only if it is intra-, extra-, and inter-conformant altogether.
The implementation of Custom Datatype Length is available at URL http://w3id.org/lindt/v1/custom_datatypes
The implementation of Jena and ARQ with support for on-the-fly recognition of custom datatypes is available at URL https://github.com/thesmartenergy/jena
datasets files, are based on DBpedia 2014 English specific mapping-based properties dataset.
The test program is bundled in a Maven project DBpediaLengthQueries
The following are the [sparql11-query] requests that are evaluated on each dataset.
Dataset dbpediaPREFIX dbpdt: <http://dbpedia.org/datatype/> SELECT ?x ?prop ?length ?metres WHERE { VALUES (?factor ?unit) { (0.001 dbpdt:millimetre) (0.01 <http://dbpedia.org/datatype/centimetre>) (1 <http://dbpedia.org/datatype/metre>) (1000 <http://dbpedia.org/datatype/kilometre>) } ?x ?prop ?length . BIND (?factor*<http://www.w3.org/2001/XMLSchema#decimal>(?length) as ?metres) FILTER(datatype(?length) = ?unit) FILTER( ?metres < 5 ) } ORDER BY DESC ( ?metres ) LIMIT 100Dataset custom
PREFIX cdt: <http://w3id.org/lindt/v1/custom_datatypes#> SELECT ?x ?prop ?length WHERE { ?x ?prop ?length . FILTER(datatype(?length) = cdt:length ) FILTER( ?length < "5m"^^cdt:length ) } ORDER BY DESC (?length) LIMIT 100Dataset qudt
PREFIX qudt: <http://qudt.org/schema/qudt#> PREFIX qudt-unit: <http://qudt.org/vocab/unit#> SELECT ?x ?prop ?length (?factor*?length as ?metres) WHERE { VALUES (?factor ?unit) { (0.001 qudt-unit:millimetre) (0.01 qudt-unit:centimetre) (1 qudt-unit:metre) (1000 qudt-unit:kilometre) } ?x ?prop [ qudt:quantityValue [ qudt:numericValue ?length ; qudt:unit ?unit ] ] . FILTER( ?factor*?length < 5 ) } ORDER BY DESC (?metres) LIMIT 100
lindt.dbpedialengthqueries.Main