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)