Live mode — this page may load external map tiles and query remote endpoints; the standard hub is fully self-contained (same cells, no network).

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.

A dataset with triple terms#

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"})

Statements as values#

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

Matching inside a triple term#

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

Annotations carry provenance#

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

What's here, and what isn't yet#

Landed and verified (no --lax), and — as of this post — reachable from the browser and the npm package, not just the w3c_runner:

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.