Same RO-Crate
+ Convention for interoperable schema and metadata.
+ Convention to include interoperable schema and metadata outside ro-crate-metadata.json.
| Profile | Status | Version | Comments |
|---|---|---|---|
| Interoperability Profile | Release | 0.2 | |
| Extensibility Profile | Draft | 0.1 |
| Profile | Status | Version | Comments |
|---|---|---|---|
| Client API | Release | 0.2 | Read/write RO-crates containing schema and metadata |
| Server API | Draft | 1.0 | Exports/imports RO-crates containing schema and metadata |
| Language | Status | Interoperability Profile | Extensibility Profile | Comments |
|---|---|---|---|---|
| Java | Release Candidate | 0.2 | Reference implementation | |
| Python | Release Candidate | 0.2 | Python implementation with Pydantic support |
| Application | Status | Interoperability Profile | Extensibility Profile | Comments |
|---|---|---|---|---|
| openBIS | Active Development | 0.2 | ||
| SciCat | Active Development | 0.2 | ||
| SciLog | Active Development | 0.2 | ||
| AiiDAlab | Planned |
In this example, we express two SQL tables in RO-Crate. It expresses experiments and each experiment can have a creator, who is a person.
SQL example source
CREATE TABLE person( -- https://schema.org/Person
personid VARCHAR(255),
givenname VARCHAR(255), -- https://schema.org/givenName
familyname VARCHAR(255), -- https://schema.org/familyName
identifier VARCHAR (255), -- https://schema.org/identifier
PRIMARY KEY(personid)
);
CREATE TABLE experiment(
experimentid VARCHAR(255),
date DATETIME,
name VARCHAR(255),
creatorid VARCHAR(255), https://schema.org/creator
PRIMARY_KEY(experimentid),
FOREIGN KEY(creatorid) REFERENCES person(personid)
);
INSERT INTO PERSON (person_id, givenname, familyname, identifier) VALUES ('PERSON1', 'Meier', 'Andreas', 'https://orcid.org/0009-0002-6541-4637');
INSERT INTO PERSON (person_id, givenname, familyname, identifier) VALUES ('PERSON2', 'Fuentes', 'Juan', 'https://orcid.org/0009-0002-8209-1999');
INSERT INTO experiment (experimentid, date, name, creatorid) VALUES ('EXPERIMENT1', '2025-09-08 08:41:50', 'Example Experiment', 'Person1');
Tables are Types in our nomenclature, e.g.
IType personType = new Type()
Columns are PropertyTypes, e.g.
IPropertyType name = new PropertyType()
Both Types and PropertyTypes can be annotated to specify semantics.
The rows are represented by IMetaDataEntry, their IType is specifed in the crate.
Java example source
import ch.eth.sis.rocrate.SchemaFacade;
import ch.eth.sis.rocrate.facade.*;
import edu.kit.datamanager.ro_crate.writer.FolderWriter;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class QuickStartWrite
{
private static final String PREFIX = "Example";
private static final String SEPARATOR = ":";
public static final String TMP_EXAMPLE_CRATE = "/tmp/example-crate";
public static void main(String[] args)
{
/* Setting up an RO-Crate with the schema facade */
ISchemaFacade schemaFacade =
new SchemaFacade("name", "description", "2024-12-04T07:53:11Z", "licenceIdentifier",
Map.of());
Type personType = new Type();
{
personType.setId(PREFIX + SEPARATOR + "Person");
personType.setOntologicalAnnotations(List.of("https://schema.org/Person"));
{
PropertyType personId = new PropertyType();
personId.setId(PREFIX + SEPARATOR + "personid");
personId.setTypes(List.of(LiteralType.STRING));
personType.addProperty(personId);
}
{
PropertyType givenName = new PropertyType();
givenName.setId(PREFIX + SEPARATOR + "givenName");
givenName.setOntologicalAnnotations(List.of("https://schema.org/givenName"));
givenName.setTypes(List.of(LiteralType.STRING));
personType.addProperty(givenName);
}
{
PropertyType givenName = new PropertyType();
givenName.setId(PREFIX + SEPARATOR + "familyName");
givenName.setOntologicalAnnotations(List.of("https://schema.org/familyName"));
givenName.setTypes(List.of(LiteralType.STRING));
personType.addProperty(givenName);
}
{
PropertyType identifier = new PropertyType();
identifier.setId(PREFIX + SEPARATOR + "identifier");
identifier.setOntologicalAnnotations(List.of("https://schema.org/identifier"));
identifier.setTypes(List.of(LiteralType.STRING));
personType.addProperty(identifier);
}
schemaFacade.addType(personType);
}
Type experimentType = new Type();
/* Building our Experiment type */
{
experimentType.setId(PREFIX + SEPARATOR + "Experiment");
{
PropertyType experimentId = new PropertyType();
experimentId.setId(PREFIX + SEPARATOR + "experimentid");
experimentId.setTypes(List.of(LiteralType.STRING));
experimentType.addProperty(experimentId);
}
{
PropertyType creator = new PropertyType();
creator.setId(PREFIX + SEPARATOR + "creator");
creator.setOntologicalAnnotations(List.of("https://schema.org/creator"));
creator.addType(personType);
experimentType.addProperty(creator);
}
{
PropertyType name = new PropertyType();
name.setId(PREFIX + SEPARATOR + "name");
name.setTypes(List.of(LiteralType.STRING));
experimentType.addProperty(name);
}
{
PropertyType date = new PropertyType();
date.setId(PREFIX + SEPARATOR + "date");
date.setTypes(List.of(LiteralType.DATETIME));
experimentType.addProperty(date);
}
schemaFacade.addType(experimentType);
}
{
MetadataEntry personAndreas = new MetadataEntry();
personAndreas.setId("PERSON1");
Map properties = new LinkedHashMap<>();
personAndreas.setTypes(Set.of(personType.getId()));
properties.put("givenname", "Andreas");
properties.put("lastname", "Meier");
properties.put("identifier", "https://orcid.org/0009-0002-6541-4637");
personAndreas.setProps(properties);
personAndreas.setReferences(new LinkedHashMap<>());
schemaFacade.addEntry(personAndreas);
MetadataEntry personJuan = new MetadataEntry();
personJuan.setId("PERSON2");
personJuan.setTypes(Set.of(personType.getId()));
Map properties2 = new LinkedHashMap<>();
properties2.put("givenname", "Andreas");
properties2.put("lastname", "Meier");
properties2.put("identifier", "https://orcid.org/0009-0002-6541-4637");
personJuan.setProps(properties2);
personJuan.setReferences(new LinkedHashMap<>());
schemaFacade.addEntry(personJuan);
MetadataEntry experiment1 = new MetadataEntry();
experiment1.setId("EXPERIMENT1");
experiment1.setReferences(Map.of("creator", List.of(personAndreas.getId())));
experiment1.setTypes(Set.of(experimentType.getId()));
Map propertiesExperiment = new LinkedHashMap<>();
propertiesExperiment.put("name", "Example Experiment");
propertiesExperiment.put("date", "2025-09-08 08:41:50.000");
experiment1.setProps(propertiesExperiment);
schemaFacade.addEntry(experiment1);
}
FolderWriter folderWriter = new FolderWriter();
folderWriter.save(schemaFacade.getCrate(), TMP_EXAMPLE_CRATE);
}
}
Java example source
import ch.eth.sis.rocrate.SchemaFacade;
import ch.eth.sis.rocrate.facade.IMetadataEntry;
import ch.eth.sis.rocrate.facade.IPropertyType;
import ch.eth.sis.rocrate.facade.IType;
import com.fasterxml.jackson.core.JsonProcessingException;
import edu.kit.datamanager.ro_crate.RoCrate;
import edu.kit.datamanager.ro_crate.reader.FolderReader;
import edu.kit.datamanager.ro_crate.reader.RoCrateReader;
import java.util.List;
public class QuickStartRead
{
public static void main(String[] args) throws JsonProcessingException
{
RoCrateReader reader = new RoCrateReader(new FolderReader());
RoCrate crate = reader.readCrate(QuickStartWrite.TMP_EXAMPLE_CRATE);
SchemaFacade schemaFacade = SchemaFacade.of(crate);
List types = schemaFacade.getTypes();
/* Writes out all types with their entries */
for (IType type : types)
{
System.out.println(type);
for (IMetadataEntry entry : schemaFacade.getEntries(type.getId()))
{
System.out.println(entry);
}
}
/* Writes out all property types */
for (IPropertyType propertyType : schemaFacade.getPropertyTypes())
{
System.out.println(propertyType);
}
}
}
In this example, we express two SQL tables in RO-Crate using Python. It expresses experiments and each experiment can have a creator, who is a person.
SQL example source
CREATE TABLE person( -- https://schema.org/Person
personid VARCHAR(255),
givenname VARCHAR(255), -- https://schema.org/givenName
familyname VARCHAR(255), -- https://schema.org/familyName
identifier VARCHAR (255), -- https://schema.org/identifier
PRIMARY KEY(personid)
);
CREATE TABLE experiment(
experimentid VARCHAR(255),
date DATETIME,
name VARCHAR(255),
creatorid VARCHAR(255), https://schema.org/creator
PRIMARY_KEY(experimentid),
FOREIGN KEY(creatorid) REFERENCES person(personid)
);
INSERT INTO PERSON (person_id, givenname, familyname, identifier) VALUES ('PERSON1', 'Meier', 'Andreas', 'https://orcid.org/0009-0002-6541-4637');
INSERT INTO PERSON (person_id, givenname, familyname, identifier) VALUES ('PERSON2', 'Fuentes', 'Juan', 'https://orcid.org/0009-0002-8209-1999');
INSERT INTO experiment (experimentid, date, name, creatorid) VALUES ('EXPERIMENT1', '2025-09-08 08:41:50', 'Example Experiment', 'Person1');
Tables are Types in our nomenclature, e.g.
personType = Type(id="id")
Columns are PropertyTypes, e.g.
name = TypeProperty(id="id")
Both Types and PropertyTypes can be annotated to specify semantics.
The rows are represented by MetadataEntry, their Type is specified in the crate.
Python example source
from lib_ro_crate_schema.crate.schema_facade import SchemaFacade
from lib_ro_crate_schema.crate.type import Type
from lib_ro_crate_schema.crate.type_property import TypeProperty
from lib_ro_crate_schema.crate.metadata_entry import MetadataEntry
from lib_ro_crate_schema.crate.literal_type import LiteralType
TMP_EXAMPLE_CRATE = "output_crates/example-crate"
# Setting up an RO-Crate with the schema facade
schemaFacade = SchemaFacade()
personType = Type(id="id")
# Building Person type
personType.setId("Person")
personType.setOntologicalAnnotations(["https://schema.org/Person"])
personId = TypeProperty(id="id")
personId.setId("personid")
personId.setTypes([LiteralType.STRING])
personType.addProperty(personId)
givenName = TypeProperty(id="id")
givenName.setId("givenName")
givenName.setOntologicalAnnotations(["https://schema.org/givenName"])
givenName.setTypes([LiteralType.STRING])
personType.addProperty(givenName)
familyName = TypeProperty(id="id")
familyName.setId("familyName")
familyName.setOntologicalAnnotations(["https://schema.org/familyName"])
familyName.setTypes([LiteralType.STRING])
personType.addProperty(familyName)
identifier = TypeProperty(id="id")
identifier.setId("identifier")
identifier.setOntologicalAnnotations(["https://schema.org/identifier"])
identifier.setTypes([LiteralType.STRING])
personType.addProperty(identifier)
schemaFacade.addType(personType)
# Building Experiment type
experimentType = Type(id="id")
experimentType.setId("Experiment")
experimentId = TypeProperty(id="id")
experimentId.setId("experimentid")
experimentId.setTypes([LiteralType.STRING])
experimentType.addProperty(experimentId)
creator = TypeProperty(id="id")
creator.setId("creator")
creator.setOntologicalAnnotations(["https://schema.org/creator"])
creator.addType(personType)
experimentType.addProperty(creator)
name = TypeProperty(id="id")
name.setId("name")
name.setTypes([LiteralType.STRING])
experimentType.addProperty(name)
date = TypeProperty(id="id")
date.setId("date")
date.setTypes([LiteralType.DATETIME])
experimentType.addProperty(date)
schemaFacade.addType(experimentType)
# Creating metadata entries
personAndreas = MetadataEntry(id="id", class_id="id")
personAndreas.setId("PERSON1")
personAndreas.setClassId(personType.getId())
properties = {}
properties["givenname"] = "Andreas"
properties["lastname"] = "Meier"
properties["identifier"] = "https://orcid.org/0009-0002-6541-4637"
personAndreas.setProperties(properties)
personAndreas.setReferences({})
schemaFacade.addEntry(personAndreas)
personJuan = MetadataEntry(id="id", class_id="id")
personJuan.setId("PERSON2")
personJuan.setClassId(personType.getId())
properties2 = {}
properties2["givenname"] = "Juan"
properties2["lastname"] = "Meier"
properties2["identifier"] = "https://orcid.org/0009-0002-6541-4637"
personJuan.setProperties(properties2)
personJuan.setReferences({})
schemaFacade.addEntry(personJuan)
experiment1 = MetadataEntry(id="id", class_id="id")
experiment1.setId("EXPERIMENT1")
experiment1.setClassId(experimentType.getId())
experiment1.setReferences({"creator": [personAndreas.getId()]})
propertiesExperiment = {}
propertiesExperiment["name"] = "Example Experiment"
propertiesExperiment["date"] = "2025-09-08 08:41:50.000"
experiment1.setProperties(propertiesExperiment)
schemaFacade.addEntry(experiment1)
# Write to file
schemaFacade.write(TMP_EXAMPLE_CRATE, name="Python QuickStart Example")
Python example source
from lib_ro_crate_schema.crate.schema_facade import SchemaFacade
TMP_EXAMPLE_CRATE = "output_crates/example-crate"
# Load RO-Crate from directory
schemaFacade = SchemaFacade.from_ro_crate(TMP_EXAMPLE_CRATE)
# Display types
types = schemaFacade.getTypes()
print("📚 Types in the crate:")
for typeObj in types:
print(f"- Type {typeObj.getId()}: {typeObj.getComment() if typeObj.getComment() else ''}")
entries = schemaFacade.getEntries(typeObj.getId())
for entry in entries:
print(f"{entry.getId()} ({entry.getClassId()}): {entry.properties}")
# Display property types
print("📚 Properties in the crate:")
properties = schemaFacade.getPropertyTypes()
for prop in properties:
print(f"{prop.getId()}: {prop.getComment() if prop.getComment() else ''} Range: {prop.getRange()}")
Optionally you can create a RO-Crate using Pydantic models with the decorator-based approach. For a complete example with complex scientific workflows, object relationships, and round-trip import/export, see the full example.
Minimal Pydantic example source
from pydantic import BaseModel
from lib_ro_crate_schema.crate.decorators import ro_crate_schema, Field
from lib_ro_crate_schema.crate.schema_facade import SchemaFacade
from lib_ro_crate_schema.crate.jsonld_utils import add_schema_to_crate
from rocrate.rocrate import ROCrate
from pathlib import Path
# Define a simple Person schema
@ro_crate_schema(ontology="https://schema.org/Person")
class Person(BaseModel):
"""Person entity in the RO-Crate"""
name: str = Field(json_schema_extra={"ontology": "https://schema.org/name"})
email: str = Field(json_schema_extra={"ontology": "https://schema.org/email"})
# Create a Person instance
person = Person(name="Alice Researcher", email="alice@example.org")
# Build RO-Crate
facade = SchemaFacade()
facade.add_all_registered_models()
facade.add_model_instance(person, "alice")
# Create and export RO-Crate
crate = ROCrate()
crate.name = "Minimal Example"
crate.description = "A minimal RO-Crate with one Person"
final_crate = add_schema_to_crate(facade, crate)
output_path = Path("output_crates/minimal_example")
output_path.mkdir(parents=True, exist_ok=True)
final_crate.write(output_path)
print(f"✓ RO-Crate exported to: {output_path}")