Skip to content

OO-LD/schema

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 

Repository files navigation

[DOI](https://doi.org/10.5281/zenodo.11401726 %CITAVIPICKERÂŁ10.5281/zenodo.11401726ÂŁTitel anhand dieser DOI in Citavi-Projekt ĂĽbernehmenÂŁ% )

OO-LD Schema

The Object Oriented Linked Data Schema based on JSON-LD and JSON-SCHEMA - work in process!

Overview

OO-LD Schema aims to connect the structural modelling of objects and subobjects with the modelling of the semantic relations without reinventing the wheel. It therefor combines existing standards, primary JSON-SCHEMA and a JSON-LD context in the same document.

JSON, JSON-SCHEMA and JSON-LD technology stack with OpenSemanticLab as example document store / platform

Introduction

Conventions and Terminology

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

Design Goals and Rationale

Compatibility

An OO-LD document is always a valid JSON document. This ensures that all of the standard JSON libraries work seamlessly with OO-LD documents.

An OO-LD instance document is always a valid JSON-LD document. This ensures that all of the standard JSON-LD libraries work seamlessly with OO-LD instance documents.

An OO-LD schema document is always both a valid JSON-SCHEMA document and JSON-LD remote context. This ensures that all of the standard JSON-SCHEMA and JSON-LD libraries work seamlessly with OO-LD schema documents.

Expressiveness

A OO-LD schema document allows the developer to express the syntax of a JSON instance document side by side with its semantics in a single source.

In addition, syntactical and semantic definitions can also be applied to referenced external JSON instance documents.

This allows to specify well-defined patterns in a directed graph and enables tools relying on a hierarchical object structure to produce data for and consume data from such a graph.

Interoperability

OO-LD schema documents allow to specify all information that is needed to automatically transform data between semantically equivalent but syntactically different notations.

Basic Concepts

If you are not familiar yet with JSON-SCHEMA or JSON-LD you should first have a look at dedicated tutorials like OSW JSON-SCHEMA Tutorial and OSW JSON-LD Tutorial.

The core idea is that an OO-LD document is always both a valid JSON-SCHEMA and a reference-able JSON-LD remote context as defined in JSON-LD v1.1 section 3.1 ( != JSON-LD document). In this way a complete OO-LD class / schema hierarchy is consume-able by JSON-SCHEMA-only and JSON-LD-only tools while OO-LD aware tools can provide extended features on top (e.g. UI autocomplete dropdowns for string-IRI fields based e.g. on a SPARQL backend, SHACL shape or JSON-LD frame generation).

A minimal example:

{
  "@context": {
    "schema": "http://schema.org/",
    "name": "schema:name"
  },
  "title": "Person",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "First and Last name"
    }
  }
}

You can explore this in the interactive playground

Please note that OO-LD schema documents MUST NOT be interpreted as JSON-LD documents because this would apply @context on the schema itself. The motivation behind this is to have a single document so schemas can be aggregated using both the JSON-SCHEMA $ref and the JSON-LD remote @context pointing the same resource.

%%{init: {'theme': 'neutral' } }%%
classDiagram
    class OOLD_Class_A {
        JSON-SCHEMA + JSON-LD
        @context: ...
        properties: a...
    }

    class OOLD_Class_B {
        JSON-SCHEMA + JSON-LD
        @context: ./A
        allOf: ./A
        properties: b...
    }

    class OOLD_Instance_B {
        JSON
        @context: ./B
        $schema: ./B
        a: ...
        b: ...
    }

    OOLD_Class_A <-- OOLD_Class_B: extends

    OOLD_Class_B <-- OOLD_Instance_B: type
Loading

You can read how this is implemented in OpenSemanticWorld/Lab in the introduction and schema documentation draft.

Composition

It MUST NOT be require to further process an OO-LD Schema document in order to interpret it as JSON-LD context. This implies that all occurrences of $ref in the schema are reflected in the JSON-LD context. $ref within properties of type: object MUST be listed as scoped JSON-LD context. $ref within all other property types and at the root level of the OO-LD schema MUST be listed at the root level of the JSON-LD context. In case of multiple $ref within allOf it lies within the responsibility of the importing OO-LD schema to ensure correctness of the merged remote JSON-LD context. This SHOULD NOT be applied to oneOf and anyOf since conflicts are more likely. At any time the importing OO-LD schema can define its own or override the imported JSON-LD context.

"@context"
  - B.schema.json
  - P1.schema.json
  - p1:
    "@context": P1.schema.json
  - p2:
    "@context": 
      - P2a.schema.json
      - P2b.schema.json
  - p3:
    "@context":
      keyword_in_P3a: ex:Property1
      keyword_in_P3b: ex:Property2
$id: A.schema.json
allOf:
  - $ref: B.schema.json
properties:
  p0:
    type: string
    $ref: P0.schema.json
  p1:
    type: object
    $ref: P1.schema.json
  p2:
    type: object
    allOf:
      $ref: P2a.schema.json
      $ref: P2b.schema.json
  p3:
    oneOf:
      $ref: P3a.schema.json
      $ref: P3b.schema.json
Full example
"@context": 
  name: ex:petName
$id: Pet.schema.json
properties:
  name:
    type: string
"@context": 
  name: schema:name
  pets:
    "@id": ex:hasPet
    "@context": Pet.schema.json
$id: Person.schema.json
properties:
  name:
    type: string
  pets:
    type: array
    items: 
      $ref: Pet.schema.json
"@context": Person.schema.json
$schema: Person.schema.json
name: Max
pets:
  - name: Bruno
"@context": 
  name: ex:name
  pets:
    "@id": ex:hasPet
    "@context":
      name: ex:petName
$schema: Person.schema.json
name: Max
pets:
  - name: Bruno
_:b0 <ex:hasPet> _:b1 .
_:b0 <schema:name> "Max" .
_:b1 <ex:petName> "Bruno" .

Schema Instances

https://json-schema.org/draft/2020-12/json-schema-core#name-linking-to-a-schema https://json-schema.org/draft/2020-12/json-schema-core#name-the-schema-keyword

"@context": Person.schema.json
$schema: Person.schema.json

Standard extensions

JSON-LD

Current support covers [v1.1] (https://www.w3.org/TR/json-ld/).

Multi-Mapping

JSON-LD allows only a single keyword-IRI mapping (or more precisely, ignores all but the last mapping). Currently there is no way to express that a property has two ids (e. g. with "label": {"@id": ["schema:name", "skos:prefLabel"]}, see also json-ld/json-ld.org#160). As a workaround, an additional context notation is provided: <property>*(*) pointing to additional @id mappings to provide at least a documentation for alternative options or custom RDF generation.

see also: #12

{
    "@context": [
        {
            "@version": 1.1,
            "skos": "https://www.w3.org/TR/skos-reference/",
            "schema": "https://schema.org/",
            "label": "skos:prefLabel",
            "label*": "schema:name",
            "label**": "..."
        }
    ],
    "label": "test"
}

Default JSON-LD processing would only interpret the preferred mapping:

_:b0 <skos:prefLabel> "test" .

An OO-LD aware convert could also produce redundant triples for interoperability reasons:

_:b0 <skos:prefLabel> "test" .
_:b0 <schema:name> "test" .

Furthermore, this notation can be used for data transformation and normalization, see #11

JSON-SCHEMA

Current support covers [Draft 4] (https://json-schema.org/specification-links#draft-4).

Multilanguange support

Keywords title and description can be extended with additional keywords title* and description*, which hold and object with lang-keys (de, en, etc.) pointing to the translated strings. Mapping of title*[lang] must be provided by schema preprocessing.

{
    "title": "Default Title",
    "title*": {"en": "Title (en)", "de": "Titel (de)"}
}

Range of properties

JSON-SCHEMA itself supports linked data only in form of subobject. References to independent external object are just URL-strings without any further restrictions. To express constrains on the type of the object as we know it from OWL and SHACL the keyword range is introduced (see also json-schema-org/json-schema-vocabularies#55). Note: Same as $ref, range must point to a resolvable resource.

Draft v0.1:

range is an IRI. While this is concise, there's no way to express unions and intersections of multiple schemas.

{
  "@context": {
    "schema": "http://schema.org/",
    "works_for": "schema:worksFor"
  },
  "title": "Person",
  "type": "object",
  "properties": {
    "works_for": {
      "type": "string",
      "range": "schema:Organization",
      "description": "IRI pointing to an instance of schema:Organization",
    }
  }
}
Draft v0.2:

range is an OO-LD schema. By using ...Of keywords, unions (anyOf / oneOf) and intersections (allOf) of multiple schemas can be expressed.

This will allow the following constellations:

Inline type restriction
"range": {
  "@context": {
    "schema": "http://schema.org/",
    "type": "@type"
  },
  "properties": {
    "type": {
      "type": "string",
      "const": "schema:Organization",
    }
  }
}
Reference to existing schema
"range": {
  "allOf": {
    "$ref": "Organization.schema.json"
  }
}
Full Example:
{
  "@context": {
    "schema": "http://schema.org/",
    "works_for": "schema:worksFor",
    "type": "@type"
  },
  "$id": "Person.schema.json",
  "title": "Person",
  "type": "object",
  "properties": {
    "type": {
      "type": "string",
      "const": "schema:Person",
    },
    "works_for": {
      "type": "string",
      "range": {
        "allOf": {
          "$ref": "Organization.schema.json"
        }
      },
      "description": "IRI pointing to an instance of schema:Organization",
    }
  }
}
{
  "@context": {
    "schema": "http://schema.org/",
    "type": "@type"
  },
  "$id": "Organization.schema.json",
  "title": "Organization",
  "type": "object",
  "properties": {
    "type": {
      "type": "string",
      "const": "schema:Organization",
    }
  }
}

On the downside, range may build up large schema graphs with circular paths which can raise issues in JSON-SCHEMA bundlers following all $ref relations. However, [JSON-SCHEMA]{#JSONSCHEMA202012} recommends standard bundlers not to follow $ref within custom keywords in section 9.4.2. See also https://json-schema.org/blog/posts/bundling-json-schema-compound-documents.

UI Generation

Additional keywords defined by JSON-SCHEMA Editor, see Basic features and Further details

Code Generation

In general we want to keep keywords in 'instance' JSON-documents (=> property names in schemas) strict ^[A-z_]+[A-z0-9_]*$ to avoid escaping or replacing when mapping to other languages. This works well with aliasing, e.g.

{
  "@context": {
    "schema": "http://schema.org/",
    "name": "schema:name",
    "type": "@type"
  },
  "title": "Person",
  "type": "object",
  "properties": {
    "type": {
      "type": "string",
      "default": "schema:Person",
    },
    "name": {
      "type": "string",
      "description": "First and Last name",
    }
  }
}

Python

The Person schema above translates smoothly to python (pydantic) via https://github.com/koxudaxi/datamodel-code-generator:

class Person(BaseModel):
    type: Optional[str] = "schema:Person"
    name: Optional[str] = None
    """First and Last name"""

what would not be the case if we use @type or schema:name as property names (See also python playground). From pydantic it's also straight forward to generate JSON- / OpenAPI-Schemas, especially via FastAPI.

Tooling

IANA Considerations

Slot File extension (recommended) Media type RFC6906 profile Description
schema *.schema.json application/oold-schema+json - Full OO-LD schema
schema *.schema.json application/oold-schema+json oold-schema#bundled Full OO-LD schema with all $ref and remote context bundled
schema *.schema.json application/oold-schema+json http://www.w3.org/ns/json-ld#context Only the JSON-LD context
schema *.schema.json application/ld+json - Only the JSON-LD context
schema *.schema.json application/schema+json - Only the JSON-SCHEMA schema
data *.data.json application/oold-schema-instance+json - Full OO-LD instance
data *.data.json application/ld+json http://www.w3.org/ns/json-ld#* Full OO-LD instance. Profiles defined in https://www.w3.org/TR/json-ld/#iana-considerations apply
data *.data.json application/json - Only the JSON data

Security considerations

Both security consideration of JSON-LD v1.1 section C and JSON-SCHEMA 2020-12 section 13 apply.

Registry

Discussion

Normative References

RFC 2119 Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, https://www.rfc-editor.org/info/rfc2119.
RFC 8259 Bray, T., Ed., "The JavaScript Object Notation (JSON) Data Interchange Format", STD 90, RFC 8259, DOI 10.17487/RFC8259, December 2017, https://www.rfc-editor.org/info/rfc8259.
JSON-LD https://www.w3.org/TR/2020/REC-json-ld11-20200716/
JSON-SCHEMA https://json-schema.org/draft/2020-12/json-schema-core
W3C.REC-ldp-20150226 Speicher, S., Arwe, J., and A. Malhotra, "Linked Data Platform 1.0", World Wide Web Consortium Recommendation REC-ldp-20150226, 26 February 2015, https://www.w3.org/TR/2015/REC-ldp-20150226.

Informative References

RFC 7049 Bormann, C. and P. Hoffman, "Concise Binary Object Representation (CBOR)", RFC 7049, DOI 10.17487/RFC7049, October 2013, https://www.rfc-editor.org/info/rfc7049.

Appendix

Related Work

OO-LD as bridge between linked data and the general software domain

Schema

Name Description
JSON-SCHEMA Base of this work. Does not include linked data concepts.
JSON-LD Base of this work. Does not restrict the structure of a json file.
OWL Focus on logical modelling. Only applicable to RDF.
SHACL Only applicable to RDF.
Asset Administration Shell Industry 4.0 related data schema for assets
Semantic Aspect Meta Model SHACL subset written in turtl, e. g. used for the data models in Catena-X
SmartDataModels JSON-SCHEMA defined data models used by FIWARE Foundation, TM Forum, OASC and IUDX
Common Data Model Business related data models developed by Microsoft
LinkML Custom schema language focussed on data modelling. Both importers and exporters to JSON-SCHEMA (and others) exists. Custom annotations for UI generation not (yet) supported (see #1618).
TreeLDR Custom linked data schema language that can be converted to JSON-SCHEMA, JSON-LD context, RDF and Rust code
REST-API-LD Annotated OpenAPI schemas with rendering support in Swagger-UI. Option to generate it from OO-LD.
dlite Custom schema language focussed on scientific data
NOMAD Custom schema language focussed on scientific data
Human Cell Atlas Data schemas for the biology and medical domain
OTTR Mixture of custom template and schema language. Limited toolset to convert from/to other formats.
TheWorldAvatar/ObjectGraphMapper Class-RDF Mapping in Java via decorators

Data

Name Description
BatteryKnowledgeGraph Battery related linked data set

Mappings

LinkML

In general LinkML schemas can be exported to JSON-SCHEMA and JSON-LD contexts in order to build a OO-LD schema. With linkml/linkml#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: "{{first_name}} {{last_name}}"
            - 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 a 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/2019-09/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: '{{first_name}} {{last_name}}'
        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: '{{first_name}} {{last_name}}'
    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):

grafik

Populating 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):

grafik

grafik

Minor unsolved issues:

  • annotations with object-values cannot be written in compact form, only with additional value-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 compareable 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

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.

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.

Person.dlite.yml

To overcome the missing expressivness 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-.

"@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

Person.oold.yml

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.

"@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.dlite.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

SherlockHolmes.oold.yml

About

The Object Oriented Linked Data Schema

Resources

License

Stars

Watchers

Forks

Packages

No packages published