Mappings¶
OO-LD can act as a bridge between several existing schema languages and data models. This page shows how selected formats map to OO-LD schemas and instances.
Asset Administration Shell¶
Asset Administration Shell combines schema and data in a single documents. Semantics are introduced by annotations keywords.
AAS¶
- assetInformation:
assetKind: Instance
globalAssetId: test
id: https://example.org/Simple_AAS
modelType: AssetAdministrationShell
submodels:
- keys:
- type: Submodel
value: https://example.org/Simple_Submodel
type: ModelReference
- id: https://example.org/Simple_Submodel
modelType: Submodel
submodelElements:
- idShort: ExampleProperty
modelType: Property
semanticId:
keys:
- type: GlobalReference
value: http://example.org/Properties/SimpleProperty
type: ExternalReference
value: exampleValue
valueType: xs:string
OO-LD Schemas¶
- id: https://example.org/Simple_AAS
x-aas-modelType: AssetAdministrationShell
- id: https://example.org/Simple_Submodel
"@context":
ExampleProperty: http://example.org/Properties/SimpleProperty
x-aas-modelType: Submodel
allOf:
$ref: https://example.org/Simple_AAS
properties:
ExampleProperty:
type: string
default: exampleValue # works like a template
OO-LD Data¶
"@context": https://example.org/Simple_Submodel
$schema: https://example.org/Simple_Submodel
ExampleProperty: exampleValue
Semantic Aspect Meta Model¶
Semantic Aspect Meta Model (SAMM) is a lightweight language to model (partial) objects (aspects) and their properties. While building on RDF and using turtle as serialization SAMM forms tree like structures like JSON Schema. Instead of IRIs, Ressources are identified with URNs which are not meant to be resolveable in the sense of linked data / semantic web.
Example (see AddressAspect.ttl for an address, stripping everything but the post code attribute):
SAMM¶
@prefix samm: <urn:samm:org.eclipse.esmf.samm:meta-model:2.1.0#> .
@prefix samm-c: <urn:samm:org.eclipse.esmf.samm:characteristic:2.1.0#> .
@prefix samm-e: <urn:samm:org.eclipse.esmf.samm:entity:2.1.0#> .
@prefix unit: <urn:samm:org.eclipse.esmf.samm:unit:2.1.0#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix : <urn:samm:io.catenax.shared.address_characteristic:4.0.0#> .
:AddressAspect a samm:Aspect ;
samm:preferredName "Address Aspect"@en ;
samm:description "Aspect used for the Characteristic :PostalAddress to reference address data."@en ;
samm:properties ( :address ) ;
samm:operations ( ) ;
samm:events ( ) .
:address a samm:Property ;
samm:preferredName "Address"@en ;
samm:description "The address of the data provider."@en ;
samm:characteristic :PostalAddress .
:PostalAddress a samm:Characteristic ;
samm:preferredName "PostalAddress"@en ;
samm:description "A characteristic to express the postal address and which is intended to be referenced by other aspects."@en ;
samm:dataType :AddressEntity .
:AddressEntity a samm:Entity ;
samm:preferredName "Address Entity"@en ;
samm:description "Entity of an address. Model follows specification of BPDM (Business Partner Data Management)."@en ;
samm:properties ( :thoroughfare :locality [ samm:property :premise; samm:optional true ] [ samm:property :postalDeliveryPoint; samm:optional true ] :country :postCode ) .
:postCode a samm:Property ;
samm:preferredName "Post Code"@en ;
samm:description "Postal code of the address."@en ;
samm:characteristic :PostCodeCharacteristic .
:PostCodeCharacteristic a samm-c:SingleEntity ;
samm:preferredName "PostCode Characteristic"@en ;
samm:description "Characteristic for defining a postcode which can consist of a type (e.g. \"REGULAR\" for zip codes) and a value (e.g. \"98765-4321\"). Model follows the specification of BPDM."@en ;
samm:dataType :PostCodeEntity .
:PostCodeEntity a samm:Entity ;
samm:preferredName "PostCode Entity"@en ;
samm:description "Entity for a postcode which consists of a type plus a value."@en ;
samm:properties ( [ samm:property :postCodeValue; samm:payloadName "value" ] [ samm:property :postCodeTechnicalKey; samm:payloadName "technicalKey" ] ) .
:postCodeValue a samm:Property ;
samm:preferredName "Post Code Value"@en ;
samm:description "The value of a post code."@en ;
samm:characteristic :PostCodeTrait ;
samm:exampleValue "98765-4321" .
:postCodeTechnicalKey a samm:Property ;
samm:preferredName "Post Code Technical Key"@en ;
samm:description "The technical key of a post code."@en ;
samm:characteristic :PostCodeTechnicalKeyCharacteristic .
:PostCodeTrait a samm-c:Trait ;
samm-c:baseCharacteristic samm-c:Text ;
samm-c:constraint :PostCodeConstraint .
:PostCodeTechnicalKeyCharacteristic a samm-c:Enumeration ;
samm:preferredName "Post Code Technical Key Characteristic"@en ;
samm:description "Characteristic for the technical key of a post code."@en ;
samm:dataType xsd:string ;
samm-c:values ( "CEDEX" "LARGE_MAIL_USER" "OTHER" "POST_BOX" "REGULAR" ) .
OO-LD Schema Example¶
see also generated JSON Schema
{
"@context": {
"type": "@type",
"PostalAddress": "urn:samm:io.catenax.shared.address_characteristic:4.0.0#PostalAddress",
"postCode": "urn:samm:io.catenax.shared.address_characteristic:4.0.0#postCode",
"PostCodeEntity": "urn:samm:io.catenax.shared.address_characteristic:4.0.0#PostCodeEntity",
"value": "urn:samm:io.catenax.shared.address_characteristic:4.0.0#postCodeValue",
"technicalKey": "urn:samm:io.catenax.shared.address_characteristic:4.0.0#postCodeTechnicalKey"
},
"description" : "A characteristic to express the postal address and which is intended to be referenced by other aspects.",
"type" : "object",
"properties" : {
"type": {
"type": "array",
"items": { "type": "string" },
"default": ["PostalAddress"]
},
"postCode" : {
"description" : "Postal code of the address. Entity for a postcode which consists of a type plus a value.",
"type" : "object",
"properties" : {
"type": {
"type": "array",
"items": { "type": "string" },
"default": ["PostCodeEntity"]
},
"value" : {
"description" : "The value of a post code.",
"type" : "string",
"pattern" : "^[a-z0-9][a-z0-9\\- ]{0,10}$"
},
"technicalKey" : {
"description" : "The technical key of a post code.",
"type" : "string",
"enum" : [ "CEDEX", "LARGE_MAIL_USER", "OTHER", "POST_BOX", "REGULAR" ]
}
},
"required" : [ "value", "technicalKey" ]
},
"country" : {...}
},
"required" : [ "postCode", "..." ]
}
Data instance¶
{
"address" : {
"postCode" : {
"value" : "98765-4321",
"technicalKey" : "CEDEX"
}
}
}
LinkML¶
In general LinkML schemas can be exported to JSON Schema and JSON-LD contexts in order to build a OO-LD schema. With https://github.com/linkml/linkml/pull/2369 lifecycle methods being added to the LinkML jsonschemagen which allow to use annotations to extend the generated schema.
As an example applying OOLDSchemaGenerator.py
from pprint import pprint
from linkml.generators.jsonschemagen import JsonSchemaGenerator, JsonSchema
from linkml.generators.jsonldcontextgen import ContextGenerator
import jsonasobj2
import json
import yaml
class OOLDSchemaGenerator(JsonSchemaGenerator):
def generate_annotations(self, target):
annotations = jsonasobj2._jsonobj.as_dict(target.source.annotations)
schema_annotations = {}
for key in annotations:
schema_annotations[annotations[key]['tag']] = annotations[key]['value']
if len(annotations) > 0:
target.schema_ = {**target.schema_, **schema_annotations}
return target
def after_generate_class(self, cls, sv):
self.generate_annotations(cls)
return cls
def after_generate_class_slot(self, slot, cls, sv):
self.generate_annotations(slot)
return slot
def generate(self):
_schema = super().generate()
_context = json.loads(ContextGenerator(self.schema).serialize())
oold = JsonSchema({"@context": _context["@context"], **_schema})
return oold
def serialize(self, **kwargs) -> str:
return self.generate().to_json(sort_keys=False, indent=self.indent if self.indent > 0 else None)
if __name__ == "__main__":
print(yaml.dump(json.loads(OOLDSchemaGenerator('Person.min.linkml.yaml', include_null=False).serialize()), sort_keys=False, indent=2))
on an annotated LinkML schema, e.g.
Person.linkml.yaml
id: https://example.org/Person/
name: Person
prefixes:
linkml: https://w3id.org/linkml/
schema: http://schema.org/
imports:
- linkml:types
classes:
Organization:
class_uri: schema:Organization
attributes:
name:
slot_uri: schema:name
range: string
Address:
class_uri: schema:PostalAddress
attributes:
street:
range: string
slot_uri: schema:street
city:
range: string
slot_uri: schema:city
postal_code:
range: string
slot_uri: schema:postalCode
Person:
tree_root: true
class_uri: schema:Person
attributes:
name:
slot_uri: schema:name
range: string
description: the name of a person
required: true
annotations:
- tag: options
value:
hidden: false
- template: " "
- tag: watch
value:
first_name: first_name
last_name: last_name
first_name:
range: string
last_name:
range: string
birth_date:
slot_uri: schema:birthDate
range: date
recommended: true
annotations:
title: Birth date
address:
slot_uri: schema:address
range: Address
employer:
name: employer
range: Organization
inlined: false
inlined_as_list: false
produces an OO-LD schema (JSON-LD context + JSON Schema with additional annotation for userinterface generation like, e.g. options and template)
Person.oold.yaml
'@context':
xsd: http://www.w3.org/2001/XMLSchema#
Person:
'@id': schema:Person
linkml: https://w3id.org/linkml/
schema: http://schema.org/
'@vocab': https://example.org/Person/
city:
'@id': schema:city
postal_code:
'@id': schema:postalCode
street:
'@id': schema:street
name:
'@id': schema:name
address:
'@type': '@id'
'@id': schema:address
birth_date:
'@type': xsd:date
'@id': schema:birthDate
employer:
'@type': '@id'
'@id': employer
first_name:
'@id': first_name
last_name:
'@id': last_name
Address:
'@id': schema:PostalAddress
Organization:
'@id': schema:Organization
$schema: https://json-schema.org/draft/2020-12/schema
$id: https://example.org/Person/
metamodel_version: 1.7.0
version: null
title: Person
type: object
additionalProperties: true
$defs:
Organization:
type: object
additionalProperties: false
description: ''
properties:
name:
type: string
title: Organization
Address:
type: object
additionalProperties: false
description: ''
properties:
street:
type: string
city:
type: string
postal_code:
type: string
title: Address
Person:
type: object
additionalProperties: false
description: ''
properties:
name:
type: string
description: the name of a person
options:
hidden: false
template: ' '
watch:
first_name: first_name
last_name: last_name
first_name:
type: string
last_name:
type: string
birth_date:
type: string
format: date
title: Birth date
address:
$ref: '#/$defs/Address'
employer:
$ref: '#/$defs/Organization'
required:
- name
title: Person
description: ''
properties:
name:
type: string
description: the name of a person
options:
hidden: false
template: ' '
watch:
first_name: first_name
last_name: last_name
first_name:
type: string
last_name:
type: string
birth_date:
type: string
format: date
title: Birth date
address:
$ref: '#/$defs/Address'
employer:
$ref: '#/$defs/Organization'
required:
- name
which can be copy-pasted into OO-LD playground
to get an auto-generated userinterface (based on https://github.com/json-editor/json-editor):
Populating x-oold-range in combination with a proper backend allows user to created non-inlined objects on the fly or link (= store the IRI) to existing ones (see https://opensemantic.world / https://demo.open-semantic-lab.org):
Minor unsolved issues:
annotationswith object-values cannot be written in compact form, only with additionalvalue-key in between- some information already encoded in LinkML is not yet part of the generated JSON Schema (e.g. default values)
NOMAD¶
NOMAD schemas have comparable concepts about reusable objects (sections) with typed properties (quantities). Example:
definitions:
sections:
Element:
quantities:
label:
type: str
density:
type: np.float64
unit: g/cm**3
isotopes:
type: int
shape: ['*']
Composition:
quantities:
composition:
type: str
sub_sections:
elements:
section: Element
repeats: true
can be expressed as the following JSON Schema (formated as yaml)
definitions:
sections:
Element:
properties:
label:
type: string
density:
type: number
unit: g/cm**3
isotopes:
type: array
items:
type: integer
format: table
Composition:
properties:
composition:
type: str
elements:
type: array
format: table
items:
$ref: '#/definitions/sections/Element'
generating/validating the same JSON/YAML data (see also playground), e.g.
composition: H2O
elements:
- label: H
density: 8.375e-05
isotopes: [1, 2, 3]
- label: O
density: 1.141
isotopes: [16, 17, 18]
by using the following mapping (work in progress):
| NOMAD Schema | JSON Schema | Note |
|---|---|---|
| quantities | properties | |
| type (int, str, ...) | type (integer, string, ...) | specific python types like np.int32 can be annotated in the JSON-LD context |
| unit, m_annotations, .. | format / options | additional custom annotation keywords can be kept or mapped to format and options |
| shape[*] | type: array, items: type: number | specific values can be mapped to minItems and maxItems |
| shape[,] | type: array, items: type: array, items: type: number | nested array |
| sub_sections: ... : repeats: true | type: array, items: type: object | array of objects |
| ... |
Dlite¶
Dlite Schema¶
Dlite already uses JSON Schema keywords like properties, type and description. Similar to NOMAD, annotations unit declare the unit of measure of quantity values and shape is used to describe array dimensions. However, different from NOMAD, shape refers to parameters declared under dimensions.
Person.dlite.yml¶
uri: http://onto-ns.com/meta/0.1/Person # identifier of the schema document
meta: http://onto-ns.com/meta/0.3/EntitySchema # links to a meta schema as type
description: A person.
dimensions:
nskills: Number of skills.
properties:
general:
type: $ref
$ref: http://onto-ns.com/meta/0.1/Thing # reference to a another schema document
name:
type: string
description: Full name.
age:
type: float32
unit: year
description: Age of person.
skills:
type: string
shape: [nskills]
description: List of skills.
To overcome the missing expressiveness in JSON Schema alone, specific JSON-LD @type annotations can be used (here xsd:float). dimension, unit, and shape can be expressed with custom keywords, prefixed by x-dlite-.
Person.oold.yml¶
"@context":
xsd: http://www.w3.org/2001/XMLSchema
age:
"@type": xsd:float # see: https://www.w3.org/TR/xmlschema11-2/#float
$id: http://onto-ns.com/meta/0.1/Person
description: A person.
x-dlite-dimensions:
nskills: Number of skills.
properties:
general:
type: string
format: uri
x-oold-range: http://onto-ns.com/meta/0.1/Thing # reference to a another schema document
name:
type: string
description: Full name.
age:
type: number
x-dlite-unit: year
description: Age of person.
skills:
type: array
x-dlite-shape: [nskills]
description: List of skills.
#minItems: ? # can be set if nskills is known
#maxItems: ? # can be set if nskills is known
items:
type: string
Instance¶
On the instance level the main difference is the nesting of properties within a properties subobject. This can be interpreted as JSON-LD nested-properties. Links to other instance documents are UUIDs which should be interpreted as urn:uuid.
SherlockHolmes.dlite.yml¶
"@context":
- /remote/context/of/Person
- properties: "@nest" # skip this level
uuid: 8cbd4c09-734d-4532-b35a-1e0dd5c3e8b5
meta: http://onto-ns.com/meta/0.1/Person # like type
properties:
general: <UUID of a Thing instance document>
name: Sherlock Holmes
age: 34.0
skills:
- observing
- chemistry
- violin
- boxind
SherlockHolmes.oold.yml¶
"@context": http://onto-ns.com/meta/0.1/Person
$schema: http://onto-ns.com/meta/0.1/Person
uuid: 8cbd4c09-734d-4532-b35a-1e0dd5c3e8b5
general: urn:uuid:<UUID of a Thing instance document>
name: Sherlock Holmes
age: 34.0
skills:
- observing
- chemistry
- violin
- boxind
REST API Linked Data (x-jsonld-*)¶
REST API Linked Data Keywords attaches a JSON-LD context to each JSON Schema / OpenAPI Schema Object via x-jsonld-context and x-jsonld-type, so that JSON-LD lives inside a document that OpenAPI 3.0 accepts (OpenAPI 3.0 rejects a top-level @context). This is the same "annotate JSON Schema in place" idea as OO-LD, delivered per class instead of per document. The mapping to and from OO-LD is mechanical and reversible; the forward direction (OO-LD to an OpenAPI 3.0 bundle) is shown in Use Cases -> Delivery to OpenAPI, MCP and LLM tooling. The reverse direction ingests a REST-API-LD Schema Object into an OO-LD schema:
REST-API-LD (OpenAPI 3.0)¶
{
"components": {
"schemas": {
"Person": {
"x-jsonld-context": { "schema": "http://schema.org/", "name": "schema:name" },
"x-jsonld-type": ["schema:Person"],
"type": "object",
"properties": { "name": { "type": "string" } },
"required": ["name"]
}
}
}
}
OO-LD Schema¶
{
"@context": { "schema": "http://schema.org/", "name": "schema:name" },
"$id": "Person.schema.json",
"x-oold-instance-rdf-type": ["schema:Person"],
"title": "Person",
"type": "object",
"properties": { "name": { "type": "string" } },
"required": ["name"]
}
x-jsonld-context maps to the top-level @context and x-jsonld-type to x-oold-instance-rdf-type. Both forms produce the same triples; a bundle of several classes becomes one OO-LD schema package with cross-schema $refs.
WoT JSON Schema in RDF¶
The W3C Web of Things note JSON Schema in RDF attaches a JSON-LD context to a schema's instances with the jsonld:context property, keeping the JSON Schema keywords and the instance context in one document - the closest standards precedent for OO-LD.
WoT¶
{
"@context": { "jsonld": "http://www.w3.org/ns/json-ld#" },
"jsonld:context": "http://schema.org",
"type": "object",
"description": "Schema of a commercial product with GTIN and manufacturer",
"properties": {
"gtin14": { "type": "string" },
"manufacturer": { "type": "string" }
}
}
OO-LD Schema¶
{
"@context": "http://schema.org",
"title": "Product",
"description": "Schema of a commercial product with GTIN and manufacturer",
"type": "object",
"properties": {
"gtin14": { "type": "string" },
"manufacturer": { "type": "string" }
}
}
The jsonld:context value becomes OO-LD's top-level @context (here a remote context URL). OO-LD does not wrap the context under a jsonld: term, so the schema document is itself directly consumable as a JSON-LD remote context.
SPDX 3.0¶
SPDX 3.0 is model-driven. Its primary notation is not JSON-LD but a constrained-Markdown model (one file per class/property in the spdx-3-model repository); a spec-parser then generates the OWL ontology with SHACL shapes, the JSON-LD context, and the JSON Schema. A document is validated both structurally (JSON Schema) and semantically (SHACL). OO-LD reaches the same dual validation from a single artefact - the OO-LD schema is the JSON Schema, and its @context yields the RDF that SHACL checks - without maintaining a separate generated schema and context.
SPDX model (constrained Markdown, class Package, abbreviated)¶
# Package
## Metadata
- name: Package
- SubclassOf: /Software/SoftwareArtifact
## Properties
- packageVersion
- type: xsd:string
- minCount: 0
- maxCount: 1
- downloadLocation
- type: xsd:anyURI
- minCount: 0
- maxCount: 1
OO-LD Schema (the same class, single artefact)¶
{
"@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld",
"$id": "Package.schema.json",
"title": "Package",
"allOf": [{ "$ref": "SoftwareArtifact.schema.json" }],
"properties": {
"type": { "const": "software_Package" },
"packageVersion": { "type": "string" },
"downloadLocation": { "type": "string", "format": "uri" }
}
}
| SPDX model construct | OO-LD |
|---|---|
# Name / name: metadata |
title plus the node type constant (IRI supplied by @context) |
SubclassOf: X |
allOf: [{ "$ref": "X.schema.json" }], context inherited |
property type: xsd:* |
property type (with @type datatype coercion in @context) |
minCount: 1 |
property listed in required |
maxCount: 1 (vs unbounded) |
single value (otherwise type: array) |
| property name / path | a term IRI in @context |
The OO-LD schema reuses the SPDX-published JSON-LD context (a remote context), so the property names resolve to the same IRIs and datatypes SPDX defines and an instance validated against this schema expands to SPDX RDF. The difference is authoring: SPDX keeps the model, the JSON Schema and the context as three generated artefacts kept in sync by tooling; OO-LD keeps the one document.
Croissant (MLCommons)¶
Croissant describes ML datasets as JSON-LD built on schema.org/Dataset plus the cr: vocabulary. Unlike SPDX or LinkML there is no separate model notation to compile: a Croissant document is authored directly as JSON-LD, so its primary notation is the instance-shaped document below. Because it is already JSON-LD, an OO-LD schema over the same terms adds structural validation while preserving the semantics.
Croissant (JSON-LD, authored directly)¶
{
"@context": { "@vocab": "https://schema.org/", "cr": "http://mlcommons.org/croissant/" },
"@type": "sc:Dataset",
"name": "simple-pass",
"recordSet": [
{
"@type": "cr:RecordSet",
"@id": "images",
"field": [
{ "@type": "cr:Field", "@id": "images/image_content", "dataType": "sc:ImageObject" }
]
}
]
}
OO-LD Schema¶
{
"@context": { "sc": "https://schema.org/", "cr": "http://mlcommons.org/croissant/", "type": "@type" },
"$id": "Dataset.schema.json",
"title": "Dataset",
"type": "object",
"properties": {
"type": { "const": "sc:Dataset" },
"name": { "type": "string" },
"recordSet": {
"type": "array",
"items": {
"type": "object",
"properties": {
"type": { "const": "cr:RecordSet" },
"field": {
"type": "array",
"items": {
"type": "object",
"properties": {
"type": { "const": "cr:Field" },
"dataType": { "type": "string", "x-oold-range": "sc:ImageObject" }
}
}
}
}
}
}
}
}
OO-LD adds structural validation (required fields, cardinalities) and a machine-checkable x-oold-range on dataType, on top of Croissant's JSON-LD semantics.
Overlays Capture Architecture (OCA)¶
OCA takes the opposite approach to a single unified document: a minimal capture base carries attribute names and core data types, and separate, content-addressed (SAID) overlays add labels, formats, units, encodings and mappings. OO-LD folds those concerns into one schema; the overlay types have direct OO-LD counterparts.
OCA (capture base + label and conformance overlays, abbreviated)¶
{
"capture_base": {
"type": "spec/capture_base/1.0",
"attributes": { "full_name": "Text", "date_of_birth": "DateTime" }
},
"overlays": {
"label": { "attribute_labels": { "full_name": "Full name", "date_of_birth": "Date of birth" } },
"conformance": { "attribute_conformance": { "full_name": "M", "date_of_birth": "O" } }
}
}
OO-LD Schemas (modular, mirroring the overlays)¶
OO-LD composes with $ref plus a remote @context (see the guide's Composition section), so OCA's overlay structure maps directly onto cross-referencing OO-LD schema modules: a base capture schema carries the structure and core types, and each overlay becomes a small schema that references the base and contributes exactly one concern (labels, a localized label set, semantics, formats) - the same distributed-authorship pattern as OCA overlays.
Base capture schema (structure and core types only):
{
"$id": "Person.capture.schema.json",
"type": "object",
"properties": {
"full_name": { "type": "string" },
"date_of_birth": { "type": "string", "format": "date" }
},
"required": ["full_name"]
}
Label overlay - references the base and sets only labels (a second, differently-labelled overlay is just another such module):
{
"$id": "Person.label-en.schema.json",
"allOf": [{ "$ref": "Person.capture.schema.json" }],
"properties": {
"full_name": { "title": "Full name" },
"date_of_birth": { "title": "Date of birth" }
}
}
Semantics overlay - references the base and adds only the @context:
{
"$id": "Person.semantics.schema.json",
"@context": { "schema": "http://schema.org/", "full_name": "schema:name", "date_of_birth": "schema:birthDate" },
"allOf": [{ "$ref": "Person.capture.schema.json" }]
}
The same concerns MAY also be consolidated into one OO-LD document when modularity is not needed; both forms are valid OO-LD.
| OCA overlay | OO-LD |
|---|---|
| capture base attribute + data type | properties.<name> with type / format |
| label overlay | title (and x-oold-multilang-title for languages) |
| conformance overlay (M/O) | required |
| unit / format / encoding overlay | format, x-oold-ui-* |
| attribute mapping overlay | @context term IRI |
| a whole overlay object | a schema module that $refs the base and adds one concern |
The key difference is identity and semantics: OCA addresses overlays by content hash (SAID) and reaches meaning only through a separate attribute-mapping overlay, whereas OO-LD modules are addressed by resolvable $id and carry the IRIs natively in @context. When patching a schema owned elsewhere rather than layering new modules, OO-LD's own overlay delivery (OpenAPI Overlay actions for x-oold-ui-*) provides the "patch without editing" pattern.
TreeLDR¶
TreeLDR (SpruceID, used in the Verifiable Credentials / DID space) centres on RDF layouts. Its primary notation is a JSON layout document that maps a tree value to and from an RDF dataset (dehydrate = tree to RDF, hydrate = RDF to tree). A layout is a record of fields, each binding a tree field to an RDF property IRI and a value layout (its datatype):
TreeLDR layout (abbreviated)¶
{
"id": "https://example.org/#RecordLayout",
"type": "record",
"prefixes": { "tldr": "https://treeldr.org/prelude#" },
"fields": {
"id": { "value": { "layout": "tldr:id" } },
"name": { "value": "tldr:string", "property": "https://schema.org/name" }
}
}
OO-LD Schema¶
{
"@context": { "schema": "https://schema.org/", "name": "schema:name", "id": "@id" },
"$id": "Record.schema.json",
"type": "object",
"properties": {
"id": { "type": "string", "format": "iri" },
"name": { "type": "string" }
}
}
A layout field's property becomes an @context term IRI, its value layout becomes the JSON Schema type (with @type coercion), and the field mapped to the node identity (tldr:id) becomes @id. TreeLDR's dehydrate/hydrate is exactly OO-LD's expansion (via @context) and framing (RDF back to the tree, see the guide) - so an OO-LD schema is a layout that additionally validates. TreeLDR also compiles to JSON Schema, JSON-LD contexts and SDKs; those artefacts recombine into an OO-LD schema as in the LinkML mapping above.
yml2vocab¶
yml2vocab is a vocabulary-publishing tool (widely used by the W3C Verifiable Credentials community): from a short YAML term list it generates an RDFS vocabulary, a JSON-LD context and ReSpec HTML. It defines terms, not data schemas, so it is complementary to OO-LD: the context it produces is exactly what an OO-LD schema references in its @context.
yml2vocab (YAML term list, abbreviated)¶
vocab:
- id: ex
value: https://example.org/vocab#
class:
- id: Person
property:
- id: name
domain: Person
OO-LD Schema (consuming the generated vocabulary)¶
{
"@context": ["https://example.org/vocab/context.jsonld", { "type": "@type" }],
"$id": "Person.schema.json",
"title": "Person",
"type": "object",
"properties": {
"type": { "const": "ex:Person" },
"name": { "type": "string" }
}
}
The vocabulary and context that yml2vocab publishes for ex:Person / ex:name are referenced directly by the OO-LD schema, so the term definitions stay owned by the vocabulary while the OO-LD schema adds structure.