Skip to content

OWL / RDFS

The owl importer reads an OWL 2 ontology, or an RDFS vocabulary, in Turtle or N-Triples, into a LinkML schema. The OWL generator does the reverse, and the two should preserve most axioms of an OWL ontology.

OWL can express things LinkML cannot (property chains, defined classes, individuals). Those are lost on the way, and the importer lists them.

Terminal window
ohi get w3c/prov-o --format owl-turtle
ohi linkml from owl --schema-id https://example.org/prov \
--to prov.yaml prov-o.ttl
Try it in the playground, with PROV-O

The result has the schema, and in warnings, one line for each kind of thing that could not be imported. On the command line, add --list-not-imported to list them on stderr:

Not imported: Property chain, which LinkML cannot express (29): has_feature_kind: saref:hasFeatureKind o skos:broader; …

The import stops with an error for an IRI that can’t be a URI in the schema: an IRI that isn’t a valid URI, such as <http://example.org/q[2]>, and an IRI whose text would be read back as a CURIE, such as <xsd:string>, as xsd is a prefix of the LinkML metamodel. The same is true for an ontology IRI or --schema-id that isn’t a valid URI. The one exception is such an IRI as a reference in an annotation, such as an rdfs:seeAlso value: it doesn’t stop the import, and is kept as an annotation instead of a see_also value.

Prefix names come from sh:declare (which the generator writes), the document’s @prefix lines, the config, a list of well-known ones (rdfs, skos, dcterms, prov, sosa, …), and the last path segment of other namespaces.

The importer also reads vocabularies written in plain RDFS, such as DC terms or Schema.org:

  • rdfs:Class is imported as a LinkML class, and rdf:Property as a slot.
  • Schema.org’s schema:domainIncludes and schema:rangeIncludes are read as well.
  • RDFS can’t express that a property has one value, so every slot is multivalued.
  • A range of rdfs:Literal or rdfs:Resource says nothing, so the slot gets no range.
  • A vocabulary without an owl:Ontology gets the namespace of most of its terms as the schema id. Set it with --schema-id.
OWL LinkML
owl:Ontology the schema, with the ontology IRI as id
class, or a class used without a declaration class, named after the local part of its IRI, with class_uri when that differs from what LinkML would make. A class from another ontology becomes a class that stands for it, unless an imported schema has it (see below)
named superclasses is_a for the first superclass from the same namespace as the subclass. mixin for other superclasses.
a superclass cycle broken, since LinkML has none: a parent is left out and reported
owl:allValuesFrom on a class the slot in the class’s slots, with slot_usage range when it narrows the property’s range
owl:someValuesFrom required: true; when it narrows the range, also has_member: {range: …} (another one goes under all_of)
cardinalities required, minimum_cardinality, maximum_cardinality, exact_cardinality
owl:hasValue equals_string, with an IRI in full
a union of a class’s children as its superclass abstract: true
owl:equivalentClass to a named class exact_mappings
owl:equivalentClass to an intersection the conjuncted classes become is_a and mixins, the restrictions become slots and slot_usage.
owl:equivalentClass to a union of classes abstract: true, with the members as is_a children.
owl:equivalentClass to another expression the expression read as superclasses (the “only if” half), and reported
owl:disjointWith, owl:AllDisjointClasses disjoint_with, children_are_mutually_disjoint
owl:disjointUnionOf abstract: true and children_are_mutually_disjoint: true, with the members as is_a children
owl:hasKey unique_keys
object or data property slot, snake_cased, with slot_uri
annotation property of the ontology’s own that it describes slot with implements: [owl:AnnotationProperty]
rdfs:range range, any_of for a union, Any (from linkml:extended_types) when there is none or when it mixes classes and datatypes
rdfs:domain domain and the class’s slots; for a union, domain_of and each class’s slots
owl:FunctionalProperty single-valued. Other slots are multivalued, as OWL allows any number of values
owl:maxQualifiedCardinality 1 on xsd:string, for a property with range rdf:PlainLiteral or rdf:langString single-valued langstring slot
rdfs:subPropertyOf is_a and mixins. A parent from another ontology becomes a slot that stands for it, of the same kind as the child
owl:inverseOf, characteristics, owl:equivalentProperty inverse, transitive and friends, exact_mappings
class defined by owl:oneOf enum. The text of a value is its skos:notation, else its local name
class with only individuals, used as a range enum (turn off with enums_from_individuals: false). The class, or one of its parents, can be a range through schema:rangeIncludes too; its named equivalents become exact_mappings; and its parents become is_a and mixins, as for classes
XSD and RDF datatypes LinkML’s types, plus a type for each other one that is declared or used (int, gYear, anyURI, …)
datatype restriction minimum_value, maximum_value, minimum_length, maximum_length, pattern on the slot or the type (xsd:pattern abc becomes ^abc$).
rdfs:subClassOf on a datatype typeof when the parent is another datatype. rdfs:Literal as the parent is dropped, since every datatype is a set of literals. The datatype stays a type, not a class
a datatype defined by a list of literal values (owl:oneOf) a type with a pattern of the values, ^(Open|Closed)$. It stays a type, not an enum, so it is still a datatype after a round trip
annotations the metaslots in the config’s metadata table, then LinkML annotations for the rest, with IRI values written as full IRIs. The default table means the usual vocabularies, whatever prefixes the ontology declares
language tags the schema’s in_language when nearly all text written for people (titles, descriptions, comments and so on, not code examples or identifiers) is in one language. Text in another language, or in any language when the schema has none, keeps it, such as title: {en: Minute}. This holds for titles, descriptions, aliases, comments, notes and keywords. In a list (comments and so on), texts with a different language each are one entry; otherwise each text is an entry of its own. Annotations lose their tags

Not imported: individuals that are not part of an enum, property values of individuals, property chains, restrictions on inverse properties, general class axioms, inverse functional properties, disjoint properties, owl:imports that the config does not map, what the ontology says about terms of an imported schema, and subproperties of annotation properties and of RDF, RDFS and OWL’s own. Restrictions that do not fit slot_usage are kept in the class’s notes, like OWL: inverse ssn:hasInput min 1.

LinkML refers to classes and slots by name, so a term from another ontology needs an element in the schema. By default, the importer makes stubs for referenced-but-not-defined classes, such as Animal with class_uri: other:Animal.

When the imported ontology has a LinkML schema (e.g., it was converted to LinkML earlier), map the import to it in the config’s imports:

imports:
http://www.w3.org/ns/sosa/: sosa # the ontology IRI -> the LinkML import

The schema then imports sosa, and the importer reads that schema to use its classes, slots, enums and types by name, matching them by IRI. A relative import is resolved against where the schema is written (the directory of --to, or the current one).

In the other direction, --only-root-schema writes an owl:imports for each imported schema, with the schema’s id as the ontology IRI. A schema imported from OWL has the ontology IRI as its id (or, for a vocabulary without an owl:Ontology such as DC terms, its namespace), so the two line up.

--config takes the path to a YAML or JSON file. The JS and Python functions take the config itself, as an object or a dict, in their config option. The config’s format is defined as a LinkML schema in model/converter/importer/owl-config.yaml. Properties and classes can be written as CURIEs over the ontology’s prefixes, the config’s prefixes, or the well-known ones.

schema_id: https://example.org/my-schema # default: the ontology IRI
name: my_schema # default: the ontology's rdfs:label if it is a usable name, else the default prefix
default_prefix: d3f # default: the namespace most terms are in
prefixes:
d3f: http://d3fend.mitre.org/ontologies/d3fend.owl#
naming:
classes: keep # keep | snake | pascal | upper_snake
slots: snake # default snake: hasValue becomes has_value
permissible_values: keep
renames: # names for particular terms, by IRI or CURIE
d3f:date: date_value
metadata: # where each metaslot is read from, in order; replaces the default list for that metaslot
description: [d3f:definition, rdfs:comment]
annotations: true # keep other annotations as LinkML annotations
multivalued: true # slots are multivalued unless functional
some_values_from: required # required | range (also narrows the range, as SAREF-LinkML does)
enums_from_individuals: true
datatypes: # LinkML types for datatype IRIs
xsd:gYear: string
imports: # LinkML schemas to import in place of owl:imports (see Imports); others are reported
http://www.w3.org/ns/sosa/: ./sosa

The default metadata table reads each metaslot from the property the LinkML metamodel gives it, then from the common alternatives:

Metaslot Read from, in order
title rdfs:label, dcterms:title, dc:title, skos:prefLabel
description skos:definition, obo:IAO_0000115, rdfs:comment, dcterms:description, dc:description
aliases skos:altLabel, oboInOwl:hasExactSynonym, rdfs:label, skos:prefLabel
comments skos:note, rdfs:comment, skos:scopeNote
notes skos:editorialNote, skos:historyNote, skos:changeNote
examples skos:example, obo:IAO_0000112
see_also rdfs:seeAlso
contributors dcterms:contributor, dcterms:creator, dc:creator, dc:contributor
created_on pav:createdOn, dcterms:created, dcterms:issued
last_updated_on pav:lastUpdatedOn, dcterms:modified
license dcterms:license, dc:rights, cc:license
version pav:version, owl:versionInfo (and owl:versionIRI on the ontology)
others the property from the metamodel, such as skos:exactMatch for exact_mappings

A value goes to the first metaslot that lists its property and still has room. So a class with two rdfs:comments gets the first as its description and the second in comments. A label that is just the element’s name is dropped, and so is a comment that repeats the description.

CLI --config

How to map the ontology: names, prefixes, which annotation properties fill which metaslots, and more. See https://linkml.ohi.dev/docs/importers/owl/.

formatJsonOutputFormatdefault yaml
CLI --format

The serialization of the schema.

  • yaml YAML.
  • json JSON.
full_urisbooleandefault false
CLI --full-urisScala fullUris

Whether to write URIs in full, instead of compacting them to CURIEs with the schema's prefixes.

input_formatRdfFormatdefault ttl
CLI --input-formatScala inputFormat

The RDF syntax of the ontology. Turtle also reads N-Triples.

  • ttl Turtle, with prefixes and pretty-printed.
  • nt N-Triples, one statement per line.
schema_idstring
CLI --schema-idScala schemaId

The id of the schema to produce, instead of the schema_id of config. The default is the ontology IRI.

schemasmap of File
not on the command line

The LinkML schemas that the imports of config map owl:imports to, from file name to YAML text. By default, they are read from the file system.

OwlImportConfig

Settings for the OWL importer.

annotationsboolean

Whether to keep annotations that no metaslot uses, as LinkML annotations.

datatypesmap of DatatypeMapping

LinkML types for datatype IRIs, on top of the built-in XSD and RDF ones.

default_prefixstring

Prefix of the namespace most of the ontology's terms are in. Detected if not set.

enums_from_individualsboolean

Whether a class that is just a set of named individuals, and is the range of some property, becomes an enum. A class defined with owl:oneOf always does.

importsmap of ImportMapping

LinkML schemas to import instead of owl:imports, keyed by ontology IRI. Other owl:imports are left out with a warning.

metadatamap of MetadataSources

Annotation properties to read each metaslot from, in order of preference. Replaces the default list only for the metaslots it lists.

multivaluedboolean

Whether slots are multivalued unless the property is functional. On by default, because OWL allows any number of values.

namestring

The schema name. Defaults to the ontology's rdfs:label if it is a valid name, else the default prefix.

namingNaming

How names are made from IRIs.

prefixesmap of NamespacePrefix

Extra prefixes, on top of the ones the ontology declares.

renamesmap of TermRename

Fixed names for specific terms, keyed by IRI or CURIE.

schema_idstring

The schema id. Defaults to the ontology IRI.

some_values_fromSomeValuesFrom

How to read owl:someValuesFrom.

  • required Sets required: true on p in C. If F is narrower than the range of p, also adds has_member: {range: F}, which matches the axiom exactly.
  • range Sets required: true and range: F. This is stricter than the axiom, since every value must be an F, not just one.

DatatypeMapping

The LinkML type for a datatype IRI.

datatypestringrequired

type_namestringrequired

ImportMapping

The LinkML schema to import instead of an ontology.

ontologystringrequired

The IRI of the imported ontology.

schemastringrequired

Path to the LinkML schema, relative to where the new schema is written.

MetadataSources

The annotation properties a metaslot is read from, in order of preference.

metaslotstringrequired

propertieslist of stringrequired

Naming

How names are made from the local part of IRIs.

classesNameStyle

Style of class and enum names.

  • keep As it is.
  • snake has_value
  • pascal HasValue
  • upper_snake HAS_VALUE
permissible_valuesNameStyle

Style of permissible value names made from individuals.

  • keep As it is.
  • snake has_value
  • pascal HasValue
  • upper_snake HAS_VALUE
slotsNameStyle

Style of slot names.

  • keep As it is.
  • snake has_value
  • pascal HasValue
  • upper_snake HAS_VALUE

NamespacePrefix

A prefix and the namespace it stands for.

namespacestringrequired

prefixstringrequired

TermRename

A fixed name for a term.

new_namestringrequired

termstringrequired

The term's IRI or CURIE.

File

A file and its content.

contentstringrequired

The content of the file.

pathstringrequired

The path of the file.