Every post before this one used RDF 1.1: a graph is a set of triples,
and a triple relates three terms. RDF 1.2 — the next revision, in W3C
Working Draft as this is written — adds one structural thing and two
smaller ones. The structural change is the triple term: a triple
can now appear as a term inside another triple, so you can say things
about a statement (who claimed it, when, with what confidence)
without the awkward four-triple rdf:Statement reification of RDF 1.1.
Everything on this page runs live against the same F*-extracted engine
the W3C tests score 212 pass, 0 fail on for the RDF 1.2 syntax/eval
suites (N-Triples, N-Quads, Turtle, TriG) and 248 pass, 6 fail (of
254) for SPARQL 1.2. RDF 1.2 parsing is off by default — RDF 1.1
output stays byte-identical — so you opt in per call with
{format: "turtle12"} when parsing and {version: "1.2"} when querying.
The syntax <<( s p o )>> is a triple term. Below, :einstein :claimed <<( :light :travelsAt :c )>> is a single triple whose object
is itself the triple :light :travelsAt :c. The ~:obs {| ... |} form
is a reifier + annotation: it names an occurrence of :sunrise :happensIn :east as :obs and hangs metadata off it — the engine
expands that to :obs rdf:reifies <<( :sunrise :happensIn :east )>>
plus the annotation triple. The @ar--rtl / @en--ltr suffixes are
directional language-tagged literals — a base direction for
right-to-left scripts.
PREFIX : <http://example.org/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
VERSION "1.2"
:einstein :claimed <<( :light :travelsAt :c )>> .
:aristotle :claimed <<( :earth :hasShape :flat )>> .
:sunrise :happensIn :east ~:obs {| :confidence "0.99"^^xsd:decimal |} .
:relativity :title "نظرية النسبية"@ar--rtl .
:relativity :title "Theory of Relativity"@en--ltr .
ttl = `
PREFIX : <http://example.org/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
VERSION "1.2"
:einstein :claimed <<( :light :travelsAt :c )>> .
:aristotle :claimed <<( :earth :hasShape :flat )>> .
:sunrise :happensIn :east ~:obs {| :confidence "0.99"^^xsd:decimal |} .
:relativity :title "نظرية النسبية"@ar--rtl .
:relativity :title "Theory of Relativity"@en--ltr .
`
fn.parse(ttl, {format: "turtle12"}) runs the Turtle Mode_12 parser.
The opt-in is load-bearing: parsing is strict (issue #344), so the
same text handed to plain "turtle" (the RDF 1.1 grammar, no
triple terms) does not silently drop the <<( )>> and reifier lines
and keep the rest — it rejects the whole document, with a
ParseError naming the line and column where RDF 1.1 syntax stops
making sense. The default deliberately never changes 1.1 behaviour, so
1.2 syntax has to be asked for by name.
mode11Rejects = {
try {
await fn.parse(ttl, {format: "turtle"});
return pretty({outcome: "unexpected: Mode_11 accepted this text"});
} catch (e) {
return pretty({outcome: "rejected", name: e.name, line: e.line, column: e.column, message: e.message});
}
}
dataset = fn.parse(ttl, {format: "turtle12"})
A triple term is a first-class term, so a variable can bind to one. The
query below asks who claimed what, leaving the claimed statement whole
in ?statement — the table renders each as <<( s p o )>>.
const rows = await fn.query(dataset, `
# Who claimed which statement; ?statement binds a whole triple term.
PREFIX : <http://example.org/>
SELECT ?who ?statement WHERE { ?who :claimed ?statement }
`, {version: "1.2"});
return pretty(rows); // two rows: einstein / aristotle, each with a <<( )>> statement
The <<( ?s ?p ?o )>> pattern reaches into the triple term and binds
its three positions — so you can query the structure of the statements,
not just carry them around.
const rows = await fn.query(dataset, `
# Subject, predicate, and object of each claimed statement, matched with
# the <<( ?s ?p ?o )>> triple-term pattern.
PREFIX : <http://example.org/>
SELECT ?who ?s ?p ?o WHERE { ?who :claimed <<( ?s ?p ?o )>> }
`, {version: "1.2"});
return pretty(rows); // einstein: light/travelsAt/c ; aristotle: earth/hasShape/flat
SPARQL 1.2 also adds the isTRIPLE() test and the TRIPLE(),
SUBJECT(), PREDICATE(), OBJECT() accessors. Here isTRIPLE(?t) is
true for every claimed value because each is a triple term:
const rows = await fn.query(dataset, `
# Whether each claimed value is a triple term, tested with isTRIPLE().
PREFIX : <http://example.org/>
SELECT ?who (isTRIPLE(?t) AS ?isQuoted) WHERE { ?who :claimed ?t }
`, {version: "1.2"});
return pretty(rows); // isQuoted = true for both
The ~:obs {| :confidence 0.99 |} block attached metadata to a specific
occurrence of :sunrise :happensIn :east. That metadata is ordinary
triples, so a plain pattern reads it back:
const rows = await fn.query(dataset, `
# Confidence value attached via the ~:obs {| |} reifier and annotation.
PREFIX : <http://example.org/>
SELECT ?conf WHERE { ?obs :confidence ?conf }
`, {version: "1.2"});
return pretty(rows); // 0.99
Landed and verified (no --lax), and — as of this post — reachable
from the browser and the npm package, not just the w3c_runner:
<<( s p o )>> in N-Triples, N-Quads, Turtle, TriG,
the ~ reifier and {| |} annotation forms, the VERSION directive,
and directional literals "…"@lang--dir.TRIPLE / isTRIPLE /
SUBJECT / PREDICATE / OBJECT / base-direction builtins.Not yet implemented — do not read this page as "RDF 1.2 is finished": RDF/XML 1.2, the RDF 1.2 canonicalization (86 tests) and entailment (74 tests) suites, six residual SPARQL 1.2 evaluation cases, and RML-star mapping generation. Those are tracked under epic #305.