Liking cljdoc? Tell your friends :D

vaelii.foreign.turtle

Read an RDF graph — N-Triples, N-Quads or Turtle — as data.

This is the lexer; vaelii.foreign.rdf is the translation, and the split is the same one cycl and cyc make. Nothing here knows what rdfs:subClassOf means.

Three syntaxes, one reader. They are the same grammar at three levels of sugar, so separating them would mean three parsers that disagree about IRIs:

syntaxwhat it adds
N-Triples<s> <p> <o> . — one statement per line, no abbreviation of any kind
N-Quadsa fourth term, the graph the statement belongs to
Turtle@prefix, @base, a, ;, ,, […], (…), numeric and boolean literals

A bulk dump ships as N-Triples or N-Quads (Wikidata, YAGO, DBpedia) because a line-per-statement file streams and shards; a hand-written ontology ships as Turtle (schema.org, BFO, most of the OBO Foundry's OWL) because a person has to read it. A reader that could only take the first would be a reader you cannot point at an ontology, and one that could only take the second would not scale to a real dump.

How a term comes back. As in cycl, the namespace of a symbol is what tells two kinds apart that would otherwise collide:

RDFClojure
<http://example.org/Dog>iri/http://example.org/Dog
ex:Dog (prefix expanded)iri/http://example.org/Dog
_:b0bnode/b0
"text""text"
42, 1.5, true42, 1.5, true
"dog"@en{:lex "dog" :lang "en"}
"2020-01-01"^^xsd:date{:lex "2020-01-01" :datatype iri/…}

A literal is a plain Clojure value whenever it has nothing else to say — a language tag or a datatype vaelii has no native reading of is what makes it a map instead. That keeps the common case cheap and the tagged case honest: a Wikidata dump's labels differ only by @lang, and a reader that dropped the tag would make fifty translations of one label indistinguishable.

Blank nodes are expanded, not deferred. [ :p :o ] and ( a b c ) are abbreviations for triples about a fresh blank node, so the reader emits those triples and hands back the node — which is why one statement can yield many, and why the seq is over triples rather than over lines.

The reader is a lazy seq over a Reader, so a multi-gigabyte dump streams in constant memory.

Read an RDF graph — N-Triples, N-Quads or Turtle — as data.

This is the *lexer*; `vaelii.foreign.rdf` is the translation, and the split is the
same one `cycl` and `cyc` make.  Nothing here knows what `rdfs:subClassOf` means.

**Three syntaxes, one reader.**  They are the same grammar at three levels of sugar,
so separating them would mean three parsers that disagree about IRIs:

| syntax     | what it adds                                                     |
|------------|------------------------------------------------------------------|
| N-Triples  | `<s> <p> <o> .` — one statement per line, no abbreviation of any kind |
| N-Quads    | a fourth term, the **graph** the statement belongs to            |
| Turtle     | `@prefix`, `@base`, `a`, `;`, `,`, `[…]`, `(…)`, numeric and boolean literals |

A bulk dump ships as N-Triples or N-Quads (Wikidata, YAGO, DBpedia) because a
line-per-statement file streams and shards; a hand-written ontology ships as Turtle
(schema.org, BFO, most of the OBO Foundry's OWL) because a person has to read it.  A
reader that could only take the first would be a reader you cannot point at an
ontology, and one that could only take the second would not scale to a real dump.

**How a term comes back.**  As in `cycl`, the *namespace* of a symbol is what tells
two kinds apart that would otherwise collide:

| RDF                        | Clojure                        |
|----------------------------|--------------------------------|
| `<http://example.org/Dog>` | `iri/http://example.org/Dog`   |
| `ex:Dog` (prefix expanded) | `iri/http://example.org/Dog`   |
| `_:b0`                     | `bnode/b0`                     |
| `"text"`                   | `"text"`                       |
| `42`, `1.5`, `true`        | `42`, `1.5`, `true`            |
| `"dog"@en`                 | `{:lex "dog" :lang "en"}`      |
| `"2020-01-01"^^xsd:date`   | `{:lex "2020-01-01" :datatype iri/…}` |

A literal is a **plain Clojure value** whenever it has nothing else to say — a
language tag or a datatype vaelii has no native reading of is what makes it a map
instead.  That keeps the common case cheap and the tagged case honest: a Wikidata
dump's labels differ only by `@lang`, and a reader that dropped the tag would make
fifty translations of one label indistinguishable.

**Blank nodes are expanded, not deferred.**  `[ :p :o ]` and `( a b c )` are
abbreviations for triples about a fresh blank node, so the reader emits those triples
and hands back the node — which is why one statement can yield many, and why the seq
is over *triples* rather than over lines.

The reader is a lazy seq over a `Reader`, so a multi-gigabyte dump streams in constant
memory.
raw docstring

bnode?clj

(bnode? x)

Is x a blank node? One written _:b in the source, or one this reader minted to hold a […] or (…) abbreviation together.

Is `x` a blank node?  One written `_:b` in the source, or one this reader minted to
hold a `[…]` or `(…)` abbreviation together.
raw docstring

iriclj

(iri s)

The Clojure symbol an IRI reads as.

The Clojure symbol an IRI reads as.
raw docstring

iri-strclj

(iri-str x)

The IRI text of an iri/… symbol.

The IRI text of an `iri/…` symbol.
raw docstring

iri?clj

(iri? x)

Is x an IRI — the iri/… symbol form?

Is `x` an IRI — the `iri/…` symbol form?
raw docstring

lexclj

(lex x)

The lexical form of any literal, tagged or plain.

The lexical form of any literal, tagged or plain.
raw docstring

literalclj

(literal lexical datatype lang)

A literal from its lexical form plus an optional datatype IRI and language tag. Untagged, and tagged with a datatype we read natively, come back as plain values; a language tag always survives, since it is the only thing telling two translations of one string apart.

Public because it is the contract, not a helper: vaelii.foreign.rdfxml is a second lexer over the same graph, and two lexers that normalized literals differently would hand vaelii.foreign.rdf two different datasets for one ontology depending on which syntax it happened to be published in. A datatype and a language tag together is not a thing RDF has — pass one or the other.

A literal from its lexical form plus an optional datatype IRI and language tag.
Untagged, and tagged with a datatype we read natively, come back as plain values; a
language tag always survives, since it is the only thing telling two translations of
one string apart.

Public because it is the *contract*, not a helper: `vaelii.foreign.rdfxml` is a second
lexer over the same graph, and two lexers that normalized literals differently would
hand `vaelii.foreign.rdf` two different datasets for one ontology depending on which
syntax it happened to be published in.  A datatype and a language tag together is not
a thing RDF has — pass one or the other.
raw docstring

rdf-nsclj

The RDF namespace. Public because the syntax's own vocabulary is spelled from it in three places — here, in vaelii.foreign.rdfxml, and in vaelii.foreign.rdf — and two spellings of rdf:type would be two terms.

The RDF namespace.  Public because the syntax's own vocabulary is spelled from it in
three places — here, in `vaelii.foreign.rdfxml`, and in `vaelii.foreign.rdf` — and two
spellings of `rdf:type` would be two terms.
raw docstring

resolve-iriclj

(resolve-iri base ref)

ref resolved against base, by RFC 3986 §5.3.

This is the whole algorithm, dot segments included, and it is worth the fifty lines: xml:base in an OWL file is routinely http://example.org/dir/file with ../other hanging off it, an ontology's import closure is written in relative references, and a resolver that is merely close produces IRIs that look right and name nothing. The W3C syntax suites test exactly these cases, which is how the earlier approximation here was found to be wrong.

`ref` resolved against `base`, by RFC 3986 §5.3.

This is the whole algorithm, dot segments included, and it is worth the fifty lines:
`xml:base` in an OWL file is routinely `http://example.org/dir/file` with `../other`
hanging off it, an ontology's import closure is written in relative references, and a
resolver that is merely close produces IRIs that look right and name nothing.  The W3C
syntax suites test exactly these cases, which is how the earlier approximation here was
found to be wrong.
raw docstring

tagged?clj

(tagged? x)

Is x a literal carrying a language tag or a datatype — the map form?

Is `x` a literal carrying a language tag or a datatype — the map form?
raw docstring

triplesclj

(triples rdr)
(triples rdr opts)

Every triple rdr holds, as a lazy seq of {:s :p :o} maps — with :g on a quad. The reader is left open: the caller owns it (with-open), because the seq is consumed lazily.

opts may carry :base, for a fragment of a document whose header is elsewhere.

:strict? true makes a malformed statement throw rather than be skipped. The default is to skip, because that is what a bulk dump needs; malformed! says why both readings have to exist.

Every triple `rdr` holds, as a lazy seq of `{:s :p :o}` maps — with `:g` on a quad.
The reader is left open: the caller owns it (`with-open`), because the seq is consumed
lazily.

`opts` may carry `:base`, for a fragment of a document whose header is elsewhere.

`:strict? true` makes a malformed statement throw rather than be skipped.  The default
is to skip, because that is what a bulk dump needs; `malformed!` says why both readings
have to exist.
raw docstring

with-triplesclj

(with-triples path f)
(with-triples path f opts)

Open the RDF file at path, call (f triples) on a lazy seq of its triples, and close the file after. A .gz path is decompressed on the way through, since that is how every dump worth streaming ships. The seq is only valid inside f — it reads from the open stream.

Open the RDF file at `path`, call `(f triples)` on a lazy seq of its triples, and
close the file after.  A `.gz` path is decompressed on the way through, since that is
how every dump worth streaming ships.  The seq is only valid inside `f` — it reads
from the open stream.
raw docstring

xsdclj

The XML Schema namespace, which every datatype RDF has a native reading of lives in. Public because vaelii.foreign.rdf tests a range against it — an rdfs:range of xsd:string constrains a value rather than naming a type of term.

The XML Schema namespace, which every datatype RDF has a native reading of lives in.
Public because `vaelii.foreign.rdf` tests a range against it — an `rdfs:range` of
`xsd:string` constrains a value rather than naming a type of term.
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close