Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Turtle & OWL Correspondence

Dolfin is a source language for OWL ontologies. Compiling a package produces a single Turtle document (plus a companion N3 file for rules, and a companion SPARQL file for queries). The reverse is also supported: an OWL/RDF graph can be recovered back into a Dolfin package. This chapter describes the mapping in both directions.

Two conversions exist:

  • Dolfin → Turtle: compile a .dlf package to an OWL graph.
  • Turtle → Dolfin: reconstruct a .dlf package from an OWL graph.

The mapping is defined at the level of triples, not text. A round trip Dolfin → Turtle → Dolfin preserves the ontology’s meaning; it does not guarantee a byte-identical source file (see Round trips).


How IRIs are named

Every concept, property, and individual gets an IRI. IRIs are built from three ingredients:

  1. a base IRI (the package identity),
  2. the file path of the declaration inside the package,
  3. the local name of the entity.

The base IRI

The base IRI comes from the package declaration in package.dlf:


package <http://example.com/animals>:
  dolfin_version "1"
  version "0.1.0"

If the package is declared with an absolute IRI (<http://…>), that IRI is the base directly. If it is declared with a bare name (package animals:), the base is <compiler-base-iri>/animals, where the compiler base IRI is supplied at compile time (default http://example.org/).

File path → namespace segment

Each ontology file contributes a namespace segment derived from its path relative to the package root. A file named mammals.dlf produces the namespace IRI:

http://example.com/animals/mammals#

The filename (without .dlf) becomes the last path segment, and a # fragment terminator is appended. Nested files nest on disk and in the IRI: a file at vertebrates/mammals.dlf yields …/animals/vertebrates/mammals#.

The base namespace (declarations that belong to the package root rather than a sub-file) uses the base IRI directly with no extra path segment. On the way back, base-namespace entities are written to main.dlf.

Local names and prefix labels

An entity’s local name is its Dolfin name, joined to its namespace IRI with the # fragment separator:

DolfinIRI
concept Mammal in mammals.dlfhttp://example.com/animals/mammals#Mammal
concept Animal in the root filehttp://example.com/animals#Animal

In the emitted Turtle, entities are referenced with a prefix label taken from the filename. Mammal in mammals.dlf is written mammals:Mammal; entities in the base namespace use the empty prefix, :Animal. Each file’s namespace IRI is bound with an @prefix declaration at the top of the document.

Overriding the IRI with @iri_name

The @iri_name annotation overrides the derived IRI. It has three forms:


# Absolute: replaces the whole namespace IRI for this file
@iri_name <http://animals.kingdom/Mammalian>

# Local segment: replaces only the last path segment
@iri_name "Mammalian"      # → http://example.com/animals/Mammalian#

# On a single concept: overrides just that concept's IRI
concept Mammal:
  @iri_name <http://animals.kingdom/Mammals>

@iri_name affects only the IRI. The prefix label used to reference the entity is still derived from the filename, and sibling files and sibling concepts are unaffected.

File resources (rdfs:isDefinedBy)

To make files (and @iri_name overrides) recoverable, every emitted entity carries an rdfs:isDefinedBy triple pointing at its file resource — the file’s canonical, path-derived namespace IRI with no trailing terminator and no @iri_name override applied:

mammals:Mammal rdf:type rdfs:Class
  ; skos:prefLabel "Mammal"
  ; rdfs:isDefinedBy <http://example.com/animals/mammals> .

Each non-base file also declares its file resource and links it to the package ontology, so the package’s file set is explicit:

<http://example.com/animals/mammals> rdfs:isDefinedBy <http://example.com/animals> .

Base-namespace entities are defined by the package IRI itself (their file resource equals the owl:Ontology subject), so no self-loop is emitted.

Because the file resource is override-free, the reverse direction uses it to (1) assign each entity to its real file even when @iri_name rewrote the entity IRIs, and (2) detect that an override was used — by comparing the entity’s actual IRI against <file-resource>#<local>.


Declaration correspondence

The following table summarises the core mapping from Dolfin declarations to OWL triples.

DolfinOWL / RDF
concept CC rdf:type rdfs:Class
concept C: sub PC rdfs:subClassOf P
has p: T (T primitive)p rdf:type owl:DatatypeProperty ; rdfs:domain C ; rdfs:range xsd:…
has p: T (T a concept)p rdf:type owl:ObjectProperty ; rdfs:domain C ; rdfs:range T
enum / one of (a, b, …)owl:equivalentClass [ owl:oneOf ( … ) ] + one owl:NamedIndividual per variant
fact blockowl:NamedIndividual with rdf:type and property-value triples (the ABox)

Package metadata

Dolfin manifest fieldOWL triple on the owl:Ontology node
versionowl:versionInfo
descriptionrdfs:comment
authordc:creator (dc: = http://purl.org/dc/elements/1.1/)

Primitive types

DolfinXSD datatype
stringxsd:string
intxsd:integer
floatxsd:double
booleanxsd:boolean
datexsd:date
date_timexsd:dateTime
timexsd:time
durationxsd:duration

Quantities

A quantity(...) value is not a primitive type. It compiles to a typed literal whose datatype is a canonical unit IRI ("45"^^<https://dolfin.dev/unit/kg>), accompanied by a once-per-unit definition block that states the unit’s coefficient, dimension, and symbol with dq: predicates. See Units & Quantities for the full mapping.

Comments and labels

The name and comment attached to a declaration become SKOS annotations:

SourceOWL / SKOS
declaration nameskos:prefLabel
leading comment textskos:definition
annotated alternate labelskos:altLabel
annotated scope noteskos:scopeNote

Cardinality

A has field’s cardinality becomes an OWL restriction on the owning class:

Dolfin cardinalityOWL restriction on the class
oneowl:equivalentClass [ owl:cardinality 1 ], property is owl:FunctionalProperty
optionalowl:equivalentClass [ owl:maxCardinality 1 ], property is owl:FunctionalProperty
someowl:subClassOf [ owl:minCardinality 1 ]
exactly nowl:subClassOf [ owl:cardinality n ]
n to mowl:subClassOf [ owl:minCardinality n ; owl:maxCardinality m ]
any (default)no restriction

Property axioms

Axioms declared on a property map to OWL property characteristics:

DolfinOWL
symmetricrdf:type owl:SymmetricProperty
reflexiverdf:type owl:ReflexiveProperty
transitiverdf:type owl:TransitiveProperty
sub qrdfs:subPropertyOf q
inverse of qowl:inverseOf q
equivalent to qowl:equivalentProperty q
equivalent to ^qowl:equivalentProperty [ owl:inverseOf q ]
equivalent to a . b (chain)owl:propertyChainAxiom ( a b ) via an rdfs:subPropertyOf node
equivalent to q+transitive + propertyChainAxiom ( q self )
equivalent to q*transitive + reflexive + propertyChainAxiom ( q self )

Rules

Rules do not fit the OWL description-logic fragment. They compile to N3 (Notation3) { … } => { … } implications, written to a companion N3 document alongside the Turtle. The N3 file shares the same @prefix bindings as the Turtle so the two are consistent.


Round trips

Reconstructing Dolfin from an OWL graph works at the triple level: it reads the owl:Ontology node, the classes, properties, restrictions, individuals, and SKOS/dc/rdfs metadata, and rebuilds the package layout from rdfs:isDefinedBy (falling back to the entity IRIs when it is absent).

A Dolfin → Turtle → Dolfin round trip preserves meaning but normalises form. Keep in mind:

  • Files are rebuilt from rdfs:isDefinedBy. Each entity’s file resource names its file (…/animals/mammalsmammals.dlf); base-namespace entities land in main.dlf. Turtle that carries no rdfs:isDefinedBy (e.g. graphs not produced by this compiler) falls back to deriving the file from the entity IRI structure.
  • @iri_name overrides are reconstructed. When an entity’s IRI deviates from its file resource, the override is recovered: a file-wide, uniform deviation becomes a file-level @iri_name <ns>; an isolated one becomes a concept-level @iri_name <iri>. The recovered directive uses the absolute form (a @iri_name "segment" is recovered as the equivalent absolute IRI).
  • Entities outside the package base are dropped. Only entities defined by the package (via rdfs:isDefinedBy, or IRI-under-base in the fallback) are reconstructed. Imported/external vocabulary is treated as external and skipped.
  • dolfin_version is not carried in the graph and defaults to "1" on the way back.
  • Comments and formatting are not preserved. Only the structured annotations that became triples (rdfs:comment, SKOS labels, dc:creator) are recovered.