First commit, specification moved from https://sissource.ethz.ch/sispub/ro-crate/

This commit is contained in:
Juan Fuentes
2025-08-05 16:05:45 +02:00
parent 9bb173f4ab
commit 7f59d79c2a
40 changed files with 4926 additions and 0 deletions
Binary file not shown.
@@ -0,0 +1,581 @@
{
"@context" : [ "https://w3id.org/ro/crate/1.1/context", {
"rdfs:subClassOf" : "https://www.w3.org/TR/rdf-schema/#ch_subclassof",
"rdfs:Property" : "https://www.w3.org/TR/rdf-schema/#ch_properties",
"schema:domainIncludes" : "https://www.w3.org/TR/rdf-schema/#ch_domain",
"owl:equivalentClass" : "https://www.w3.org/TR/owl-ref/#equivalentClass-def",
"owl:equivalentProperty" : "https://www.w3.org/TR/owl-ref/#equivalentProperty-def",
"schema:rangeIncludes" : "https://www.w3.org/TR/rdf-schema/#ch_range",
"rdfs:Class" : "https://www.w3.org/TR/rdf-schema/#ch_class"
} ],
"@graph" : [ {
"name" : "name",
"description" : "description",
"@id" : "./",
"@type" : "Dataset",
"license" : {
"@id" : "licenseIdentifier"
},
"datePublished" : "2024-12-04T07:53:11Z",
"hasPart" : [ {
"@id" : "COLLECTION"
}, {
"@id" : "PUBLICATION_CREATOR"
}, {
"@id" : "hasPUBLICATION_CREATOR.IDENTIFIER_SCHEME"
}, {
"@id" : "hasPUBLICATION_CREATOR.AFFILITION_IDENTIFIER_SCHEME_URI"
}, {
"@id" : "PUBLICATION"
}, {
"@id" : "hasPUBLICATION_CREATOR.AFFILITION_IDENTIFIER_SCHEME"
}, {
"@id" : "hasPUBLICATION_CREATOR.GIVEN_NAME"
}, {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBLICATIONS_COLLECTION"
}, {
"@id" : "hasPUBLICATION.ORGANIZATION"
}, {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBCREA27"
}, {
"@id" : "hasPUBLICATION.TYPE"
}, {
"@id" : "PUBLICATIONS"
}, {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUB29"
}, {
"@id" : ":Space"
}, {
"@id" : "hasDEFAULT_COLLECTION_VIEW"
}, {
"@id" : ":Object"
}, {
"@id" : ":Vocabulary"
}, {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES"
}, {
"@id" : "hasPUBLICATION.CONTRIBUTOR"
}, {
"@id" : ":Dataset"
}, {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBLICATIONS_PUBLISHER_COLLECTION"
}, {
"@id" : "hasDEFAULT_OBJECT_TYPE"
}, {
"@id" : "hasXMLCOMMENTS"
}, {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUB25"
}, {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBLICATIONS_CREATOR_COLLECTION"
}, {
"@id" : ":Collection"
}, {
"@id" : "hasNAME"
}, {
"@id" : "hasPUBLICATION_CREATOR.IDENTIFIER"
}, {
"@id" : "hasPUBLICATION_CREATOR.AFFILITION_IDENTIFIER"
}, {
"@id" : "hasPUBLICATION_PUBLISHER.IDENTIFIER_SCHEME_URI"
}, {
"@id" : "hasPUBLICATION.IDENTIFIER"
}, {
"@id" : "hasPUBLICATION.CREATOR"
}, {
"@id" : "hasPUBLICATION.PUBLISHER"
}, {
"@id" : "hasPUBLICATION_PUBLISHER.IDENTIFIER"
}, {
"@id" : "hasPUBLICATION.PUBLICATION_YEAR"
}, {
"@id" : "hasPUBLICATION.DESCRIPTION"
}, {
"@id" : "hasPUBLICATION.OPENBIS_RELATED_IDENTIFIERS"
}, {
"@id" : ":Project"
}, {
"@id" : "PUBLICATION_PUBLISHER"
}, {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBPUB24"
}, {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBPUB26"
}, {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBCREA22"
}, {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBCREA23"
}, {
"@id" : "hasPUBLICATION.URL"
}, {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUB30"
}, {
"@id" : "hasPUBLICATION_CREATOR.FAMILY_NAME"
}, {
"@id" : "hasPUBLICATION_PUBLISHER.IDENTIFIER_SCHEME"
}, {
"@id" : "hasPUBLICATION.STATUS"
} ]
}, {
"about" : {
"@id" : "./"
},
"conformsTo" : {
"@id" : "https://w3id.org/ro/crate/1.1"
},
"@id" : "ro-crate-metadata.json",
"@type" : "CreativeWork"
}, {
"@type" : "COLLECTION",
"hasNAME" : "Publications Collection",
"hasDEFAULT_OBJECT_TYPE" : "PUBLICATION",
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBLICATIONS_COLLECTION"
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION.DESCRIPTION",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION"
},
"owl:equivalentProperty" : [ {
"@id" : "http://datacite.org/schema/kernel-4#descriptions"
}, {
"@id" : "https://schema.org/description"
}, {
"@id" : "https://schema.org/abstract"
} ]
}, {
"@id" : ":Space",
"@type" : "rdfs:Class"
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION.PUBLICATION_YEAR",
"schema:rangeIncludes" : {
"@id" : "xsd:dateTime"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION"
},
"owl:equivalentProperty" : [ {
"@id" : "http://datacite.org/schema/kernel-4#publicationYear"
}, {
"@id" : "https://schema.org/datePublished"
} ]
}, {
"@id" : ":Collection",
"@type" : "rdfs:Class"
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION.URL",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION"
},
"owl:equivalentProperty" : [ {
"@id" : "http://datacite.org/schema/kernel-4#url"
}, {
"@id" : "https://schema.org/url"
} ]
}, {
"@type" : "PUBLICATION_CREATOR",
"hasPUBLICATION_CREATOR.GIVEN_NAME" : "Elhacham",
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBCREA22"
}, {
"@id" : ":Object",
"@type" : "rdfs:Class"
}, {
"@type" : "PUBLICATION",
"hasNAME" : "Genetic mechanisms of critical illness in COVID-19",
"hasPUBLICATION.URL" : "https://www.nature.com/articles/s41586-020-03065-y#citeas",
"hasPUBLICATION.IDENTIFIER" : "https://doi.org/10.1038/s41586-020-03065-y",
"hasPUBLICATION.STATUS" : "Registered",
"hasPUBLICATION.PUBLICATION_YEAR" : "2020-12-11 15:48:55 +0100",
"hasPUBLICATION.TYPE" : "DataPaper",
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUB29",
"hasPUBLICATION.CREATOR" : {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBCREA23"
},
"hasPUBLICATION.PUBLISHER" : {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBPUB26"
}
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION_CREATOR.IDENTIFIER_SCHEME",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION_CREATOR"
}
}, {
"@type" : "COLLECTION",
"hasNAME" : "Publications creator collection",
"hasDEFAULT_OBJECT_TYPE" : "PUBLICATION_CREATOR",
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBLICATIONS_CREATOR_COLLECTION"
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION_CREATOR.GIVEN_NAME",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION_CREATOR"
},
"owl:equivalentProperty" : [ {
"@id" : "http://datacite.org/schema/kernel-4#givenName"
}, {
"@id" : "https://schema.org/givenName"
} ]
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION.IDENTIFIER",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION"
},
"owl:equivalentProperty" : [ {
"@id" : "http://datacite.org/schema/kernel-4#doi"
}, {
"@id" : "https://schema.org/identifier"
} ]
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION_PUBLISHER.IDENTIFIER_SCHEME",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION_PUBLISHER"
},
"owl:equivalentProperty" : {
"@id" : "http://datacite.org/schema/kernel-4#publisherIdentifierScheme"
}
}, {
"@type" : ":Space",
"description" : "Public Repositories",
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES"
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION_CREATOR.AFFILITION_IDENTIFIER_SCHEME_URI",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION_CREATOR"
}
}, {
"@type" : "PUBLICATION_PUBLISHER",
"hasPUBLICATION_PUBLISHER.IDENTIFIER" : "Science",
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBPUB26"
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION.CONTRIBUTOR",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION"
},
"owl:equivalentProperty" : [ {
"@id" : "http://datacite.org/schema/kernel-4#doi"
}, {
"@id" : "https://schema.org/identifier"
} ]
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION_CREATOR.FAMILY_NAME",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION_CREATOR"
},
"owl:equivalentProperty" : [ {
"@id" : "http://datacite.org/schema/kernel-4#familyName"
}, {
"@id" : "https://schema.org/familyName"
} ]
}, {
"@type" : "rdfs:Property",
"@id" : "hasDEFAULT_COLLECTION_VIEW",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "COLLECTION"
}
}, {
"@type" : "COLLECTION",
"hasNAME" : "Publications Publisher Collection",
"hasDEFAULT_COLLECTION_VIEW" : "LIST_VIEW",
"hasDEFAULT_OBJECT_TYPE" : "PUBLICATION_PUBLISHER",
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBLICATIONS_PUBLISHER_COLLECTION"
}, {
"@type" : ":Space",
"@id" : "PUBLICATIONS"
}, {
"@type" : "rdfs:Property",
"@id" : "hasXMLCOMMENTS",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION"
}
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION.ORGANIZATION",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION"
}
}, {
"@id" : "COLLECTION",
"@type" : "rdfs:Class",
"rdfs:subClassOf" : {
"@id" : ":Collection"
}
}, {
"@type" : "PUBLICATION_CREATOR",
"hasPUBLICATION_CREATOR.IDENTIFIER_SCHEME" : "https://orcid.org",
"hasPUBLICATION_CREATOR.IDENTIFIER" : "https://orcid.org/0000-0001-9844-8214",
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBCREA27"
}, {
"@type" : "PUBLICATION_CREATOR",
"hasPUBLICATION_CREATOR.IDENTIFIER_SCHEME" : "https://orcid.org/",
"hasPUBLICATION_CREATOR.IDENTIFIER" : "https://orcid.org/0000-0002-2423-3090",
"hasPUBLICATION_CREATOR.GIVEN_NAME" : "Pairo-Castineira",
"hasPUBLICATION_CREATOR.FAMILY_NAME" : "Erola",
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBCREA23"
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION.STATUS",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION"
},
"owl:equivalentProperty" : [ {
"@id" : "http://datacite.org/schema/kernel-4#stateSelection"
}, {
"@id" : "https://schema.org/creativeWorkStatus"
} ]
}, {
"@type" : "PUBLICATION",
"hasNAME" : "Global human-made mass exceeds all living biomass",
"hasPUBLICATION.URL" : "https://www.nature.com/articles/s41586-020-3010-5#citeas",
"hasPUBLICATION.IDENTIFIER" : "https://doi.org/10.1038/s41586-020-3010-5",
"hasPUBLICATION.STATUS" : "Registered",
"hasPUBLICATION.PUBLICATION_YEAR" : "2020-12-09 15:43:20 +0100",
"hasPUBLICATION.TYPE" : "DataPaper",
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUB25",
"hasPUBLICATION.CREATOR" : {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBCREA22"
},
"hasPUBLICATION.PUBLISHER" : {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBPUB24"
}
}, {
"@id" : "PUBLICATION_PUBLISHER",
"@type" : "rdfs:Class",
"rdfs:subClassOf" : {
"@id" : ":Object"
}
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION_CREATOR.AFFILITION_IDENTIFIER_SCHEME",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION_CREATOR"
}
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION_CREATOR.AFFILITION_IDENTIFIER",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION_CREATOR"
}
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION.TYPE",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION"
}
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION.CREATOR",
"schema:rangeIncludes" : {
"@id" : ":Object"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION"
},
"owl:equivalentProperty" : [ {
"@id" : "http://datacite.org/schema/kernel-4#creator"
}, {
"@id" : "https://schema.org/author"
}, {
"@id" : "https://schema.org/creator"
} ]
}, {
"@id" : ":Vocabulary",
"@type" : "rdfs:Class"
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION_CREATOR.IDENTIFIER",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION_CREATOR"
},
"owl:equivalentProperty" : [ {
"@id" : "http://datacite.org/schema/kernel-4#nameIdentifier"
}, {
"@id" : "https://schema.org/identifier"
} ]
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION_PUBLISHER.IDENTIFIER",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION_PUBLISHER"
},
"owl:equivalentProperty" : [ {
"@id" : "http://datacite.org/schema/kernel-4#publisherIdentifier"
}, {
"@id" : "https://schema.org/identifier"
} ]
}, {
"@id" : ":Project",
"@type" : "rdfs:Class"
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION_PUBLISHER.IDENTIFIER_SCHEME_URI",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION_PUBLISHER"
},
"owl:equivalentProperty" : {
"@id" : "http://datacite.org/schema/kernel-4#schemeURI"
}
}, {
"@id" : "PUBLICATION",
"@type" : "rdfs:Class",
"rdfs:subClassOf" : {
"@id" : ":Object"
}
}, {
"@type" : "PUBLICATION",
"hasNAME" : "Quantum computational advantage using photons",
"hasPUBLICATION.URL" : "https://www.science.org/doi/10.1126/science.abe8770",
"hasPUBLICATION.IDENTIFIER" : "DOI: 10.1126/science.abe8770",
"hasPUBLICATION.STATUS" : "Registered",
"hasPUBLICATION.PUBLICATION_YEAR" : "2020-12-11 15:50:44 +0100",
"hasPUBLICATION.TYPE" : "DataPaper",
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUB30",
"hasPUBLICATION.CREATOR" : {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBCREA27"
},
"hasPUBLICATION.PUBLISHER" : {
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBPUB26"
}
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION.PUBLISHER",
"schema:rangeIncludes" : {
"@id" : ":Object"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION"
},
"owl:equivalentProperty" : [ {
"@id" : "http://datacite.org/schema/kernel-4#publisher"
}, {
"@id" : "https://schema.org/publisher"
} ]
}, {
"@id" : ":Dataset",
"@type" : "rdfs:Class"
}, {
"@type" : "rdfs:Property",
"@id" : "hasDEFAULT_OBJECT_TYPE",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "COLLECTION"
}
}, {
"@type" : "rdfs:Property",
"@id" : "hasNAME",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : [ {
"@id" : "COLLECTION"
}, {
"@id" : "PUBLICATION_CREATOR"
}, {
"@id" : "PUBLICATION"
}, {
"@id" : "PUBLICATION_PUBLISHER"
} ],
"owl:equivalentProperty" : [ {
"@id" : "http://datacite.org/schema/kernel-4#title"
}, {
"@id" : "https://schema.org/headline"
}, {
"@id" : "http://datacite.org/schema/kernel-4#nameIdentifier"
}, {
"@id" : "https://schema.org/identifier"
} ]
}, {
"@type" : "PUBLICATION_PUBLISHER",
"hasPUBLICATION_PUBLISHER.IDENTIFIER" : "https://www.nature.com",
"@id" : "/PUBLICATIONS/PUBLIC_REPOSITORIES/PUBPUB24"
}, {
"@id" : "PUBLICATION_CREATOR",
"@type" : "rdfs:Class",
"rdfs:subClassOf" : {
"@id" : ":Object"
},
"owl:equivalentClass" : [ {
"@id" : "http://datacite.org/schema/kernel-4#creator"
}, {
"@id" : "https://schema.org/author"
}, {
"@id" : "https://schema.org/creator"
} ]
}, {
"@type" : "rdfs:Property",
"@id" : "hasPUBLICATION.OPENBIS_RELATED_IDENTIFIERS",
"schema:rangeIncludes" : {
"@id" : "xsd:string"
},
"schema:domainIncludes" : {
"@id" : "PUBLICATION"
},
"owl:equivalentProperty" : {
"@id" : "http://datacite.org/schema/kernel-4#relatedIdentifiers"
}
} ]
}
Binary file not shown.
+74
View File
@@ -0,0 +1,74 @@
plugins {
id 'java'
id 'application'
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
tasks.withType(JavaCompile) {
options.compilerArgs << '-parameters'
}
repositories {
ivy {
ivyPattern "https://sissource.ethz.ch/openbis/openbis-public/openbis-ivy/-/raw/main/[organisation]/[module]/[revision]/ivy.xml"
artifactPattern "https://sissource.ethz.ch/openbis/openbis-public/openbis-ivy/-/raw/main/[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]"
}
mavenCentral()
}
//'openbis:openbis-v3-api-batteries-included:6.5.0',
//files('libs/openBIS-API-V3-batteries-included-SNAPSHOT-r1718006152.jar'),
dependencies {
implementation 'com.fasterxml.jackson.core:jackson-core'
implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation 'org.slf4j:slf4j-api:2.0.16'
implementation 'edu.kit.datamanager:ro-crate-java:2.0.1'
testImplementation 'junit:junit:4.13.1'
testImplementation('jmock:jmock:2.5.1')
}
configurations.configureEach {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
// https://docs.gradle.org/current/userguide/resolution_rules.html
if (details.requested.group == 'com.fasterxml.jackson.core' && details.requested.name == 'jackson-databind') {
details.useVersion '2.18.0'
}
if (details.requested.group == 'com.fasterxml.jackson.core' && details.requested.name == 'jackson-core') {
details.useVersion '2.18.0'
}
if (details.requested.group == 'org.slf4j') {
details.useVersion '2.0.16'
}
}
}
tasks.register('buildRdfTool', Jar) {
dependsOn tasks.build
duplicatesStrategy 'include'
archiveBaseName.set('lib-rdf-tool')
includeEmptyDirs = false
manifest {
attributes(
'Main-Class': 'ch.ethz.sis.rdf.main.RDFCommandLine'
)
}
from(zipTree(tasks.jar.outputs.files.singleFile)) {
include '**/*'
}
from(configurations.runtimeClasspath.collect { zipTree(it) }) {
include '**/*'
exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA'
}
}
@@ -0,0 +1,258 @@
package ch.eth.sis.rocrate;
import ch.eth.sis.rocrate.facade.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import edu.kit.datamanager.ro_crate.RoCrate;
import edu.kit.datamanager.ro_crate.entities.data.DataEntity;
import java.io.Serializable;
import java.util.*;
public class SchemaFacade implements ISchemaFacade
{
private final static String RDFS_CLASS = "rdfs:Class";
private final static String RDFS_PROPERTY = "rdfs:Property";
public static final String EQUIVALENT_CLASS = "owl:equivalentClass";
public static final String EQUIVALENT_CONCEPT = "owl:equivalentProperty";
private Map<String, IType> types;
private Map<String, IPropertyType> propertyTypes;
private Map<String, IMetadataEntry> metadataEntries;
private final RoCrate crate;
public SchemaFacade(RoCrate crate)
{
this.crate = crate;
this.types = new LinkedHashMap<>();
this.propertyTypes = new LinkedHashMap<>();
this.metadataEntries = new LinkedHashMap<>();
}
public static SchemaFacade of(RoCrate crate) throws JsonProcessingException
{
SchemaFacade schemaFacade = new SchemaFacade(crate);
schemaFacade.parseEntities();
return schemaFacade;
}
@Override
public void addType(IType rdfsClass)
{
DataEntity.DataEntityBuilder builder = new DataEntity.DataEntityBuilder();
builder.addProperty("@id", rdfsClass.getId());
builder.addProperty("@type", RDFS_CLASS);
rdfsClass.getSubClassOf().forEach(x -> builder.addIdProperty("rdfs:subClassOf", x));
this.types.put(rdfsClass.getId(), rdfsClass);
DataEntity entity = builder.build();
entity.addIdListProperties(EQUIVALENT_CLASS, rdfsClass.getOntologicalAnnotations());
crate.addDataEntity(entity);
}
@Override
public List<IType> getTypes()
{
return this.types.values().stream().toList();
}
@Override
public IType getTypes(String id)
{
return this.types.get(id);
}
@Override
public void addPropertyType(IPropertyType rdfsProperty)
{
DataEntity.DataEntityBuilder builder = new DataEntity.DataEntityBuilder();
builder.setId(rdfsProperty.getId());
builder.addProperty("@type", RDFS_PROPERTY);
var stuff = builder.build();
stuff.addIdListProperties("schema:rangeIncludes",
rdfsProperty.getRange());
stuff.addIdListProperties("schema:domainIncludes",
rdfsProperty.getDomain());
stuff.addIdListProperties(EQUIVALENT_CONCEPT,
rdfsProperty.getOntologicalAnnotations());
crate.addDataEntity(stuff);
propertyTypes.put(rdfsProperty.getId(), rdfsProperty);
}
@Override
public List<IPropertyType> getPropertyTypes()
{
return propertyTypes.values().stream().toList();
}
@Override
public IPropertyType getPropertyType(String id)
{
return propertyTypes.get(id);
}
@Override
public void addEntry(IMetadataEntry metaDataEntry)
{
DataEntity.DataEntityBuilder builder = new DataEntity.DataEntityBuilder();
builder.setId(metaDataEntry.getId());
builder.addProperty("@type", metaDataEntry.getClassId());
ObjectMapper objectMapper = new ObjectMapper();
metaDataEntry.getValues().forEach((s, o) -> {
if (o instanceof Double)
{
builder.addProperty(s, (Double) o);
} else if (o instanceof Integer)
{
builder.addProperty(s, (Integer) o);
} else if (o instanceof Boolean)
{
builder.addProperty(s, (Boolean) o);
} else if (o instanceof String)
{
builder.addProperty(s, o.toString());
} else if (o == null)
{
builder.addProperty(s, objectMapper.nullNode());
}
});
DataEntity dataEntity = builder.build();
metaDataEntry.getReferences().forEach(dataEntity::addIdListProperties);
crate.addDataEntity(dataEntity);
}
@Override
public IMetadataEntry getEntry(String id)
{
return metadataEntries.get(id);
}
@Override
public List<IMetadataEntry> getEntries(String rdfsClassId)
{
return metadataEntries.values().stream().toList();
}
private void parseEntities() throws JsonProcessingException
{
Map<String, IPropertyType> properties = new LinkedHashMap<>();
Map<String, IType> classes = new LinkedHashMap<>();
Map<String, IMetadataEntry> entries = new LinkedHashMap<>();
for (DataEntity entity : crate.getAllDataEntities())
{
String type = entity
.getProperty("@type").asText();
String id =
entity.getProperty("@id")
.asText();
switch (type)
{
case "rdfs:Class" ->
{
RdfsClass rdfsClass = new RdfsClass();
rdfsClass.setSubClassOf(parseMultiValued(entity, "rdfs:subClassOf"));
rdfsClass.setOntologicalAnnotations(
parseMultiValued(entity, EQUIVALENT_CLASS));
rdfsClass.setId(id);
classes.put(id, rdfsClass);
}
case "rdfs:Property" ->
{
TypeProperty rdfsProperty = new TypeProperty();
rdfsProperty.setId(id);
rdfsProperty.setOntologicalAnnotations(
parseMultiValued(entity, EQUIVALENT_CONCEPT));
rdfsProperty.setRangeIncludes(
parseMultiValued(entity, "schema:rangeIncludes"));
rdfsProperty.setDomainIncludes(
parseMultiValued(entity, "schema:domainIncludes"));
properties.put(id, rdfsProperty);
}
}
}
for (var entity : crate.getAllDataEntities())
{
String type = entity
.getProperty("@type").asText();
String id =
entity.getProperty("@id")
.asText();
if (!classes.containsKey(type))
{
continue;
}
Map<String, Serializable> entryProperties = new LinkedHashMap<>();
MetadataEntry entry = new MetadataEntry();
entry.setId(id);
entry.setType(type);
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Serializable> keyVals =
objectMapper.readValue(entity.getProperties().toString(), HashMap.class);
for (Map.Entry<String, Serializable> a : keyVals.entrySet())
{
if (properties.containsKey(a.getKey()))
{
IPropertyType property = properties.get(a.getKey());
if (property.getRange().stream().anyMatch(x -> x.equals("xsd:string")))
{
entryProperties.put(a.getKey(), a.getValue().toString());
}
}
}
entry.setProps(entryProperties);
entry.setReferences(new HashMap<>());
entries.put(id, entry);
}
System.out.println("Done");
this.types = classes;
this.propertyTypes = properties;
this.metadataEntries = entries;
}
private List<String> parseMultiValued(DataEntity dataEntity, String key)
{
JsonNode node = dataEntity.getProperty(key);
if (node instanceof ObjectNode)
{
return List.of(node.get("@id").textValue());
}
if (node instanceof ArrayNode arrayNode)
{
List<String> accumulator = new ArrayList<>();
arrayNode.elements().forEachRemaining(
x -> accumulator.add(x.get("@id").textValue())
);
return accumulator;
}
return List.of();
}
}
@@ -0,0 +1,31 @@
package ch.eth.sis.rocrate.example;
import ch.eth.sis.rocrate.SchemaFacade;
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;
public class ReadExample
{
public static void main(String[] args) throws JsonProcessingException
{
String path = args.length >= 1 ? args[0] : "out";
RoCrateReader roCrateFolderReader = new RoCrateReader(new FolderReader());
RoCrate crate = roCrateFolderReader.readCrate(path);
SchemaFacade schemaFacade = SchemaFacade.of(crate);
schemaFacade.getTypes().forEach(
x -> System.out.println("RDFS Class " + x.getId())
);
schemaFacade.getPropertyTypes().forEach(
x -> System.out.println("RDFS Property " + x.getId())
);
schemaFacade.getEntries(schemaFacade.getTypes().get(0).getId()).forEach(
x -> System.out.println("Metadata entry " + x.getId())
);
}
}
@@ -0,0 +1,58 @@
package ch.eth.sis.rocrate.example;
import ch.eth.sis.rocrate.SchemaFacade;
import ch.eth.sis.rocrate.facade.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import edu.kit.datamanager.ro_crate.RoCrate;
import edu.kit.datamanager.ro_crate.writer.FolderWriter;
import java.util.List;
import java.util.Map;
public class WriteExample
{
public static void main(String[] args) throws JsonProcessingException
{
RoCrate.RoCrateBuilder roCrateBuilder =
new RoCrate.RoCrateBuilder("name", "description", "2024-12-04T07:53:11Z",
"licenseIdentifier");
ISchemaFacade schemaFacade = SchemaFacade.of(roCrateBuilder.build());
{
RdfsClass rdfsClass = new RdfsClass();
rdfsClass.setId("TextResource");
rdfsClass.setSubClassOf(List.of("https://schema.org/Thing"));
rdfsClass.setOntologicalAnnotations(
List.of("https://www.dublincore.org/specifications/dublin-core/dcmi-terms/dcmitype/Text/"));
schemaFacade.addType(rdfsClass);
TypeProperty property = new TypeProperty();
property.setId("hasDateSubmitted");
property.setTypes(List.of(LiteralType.DATETIME));
rdfsClass.addProperty(property);
property.setOntologicalAnnotations(
List.of("https://www.dublincore.org/specifications/dublin-core/dcmi-terms/terms/dateSubmitted/"));
schemaFacade.addPropertyType(property);
}
{
IMetadataEntry metadataEntry = new MetadataEntry("TextResource1", "TextResource",
Map.of("hasDate", "2025-01-21T07:12:20Z"), Map.of());
schemaFacade.addEntry(metadataEntry);
}
String path = args.length >= 1 ? args[0] : "out";
roCrateBuilder.build();
FolderWriter folderWriter = new FolderWriter();
folderWriter.save(roCrateBuilder.build(), path);
}
}
@@ -0,0 +1,21 @@
package ch.eth.sis.rocrate.facade;
public interface IDataType
{
String getTypeName();
static IDataType getArray(LiteralType literalType)
{ //TODO static IDataType getArray(LiteralType literalType)
throw new UnsupportedOperationException("Feature incomplete. Contact assistance.");
}
static IDataType getEnumerationf(String... values)
{ //TODO static IDataType getEnumerationf(String... values)
throw new UnsupportedOperationException("Feature incomplete. Contact assistance.");
}
static IDataType getCustomType(LiteralType basicType, String pattern)
{ //TODO static IDataType getCustomType(LiteralType basicType, String pattern)
throw new UnsupportedOperationException("Feature incomplete. Contact assistance.");
}
}
@@ -0,0 +1,29 @@
package ch.eth.sis.rocrate.facade;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
public interface IMetadataEntry
{
/**
* Returns the ID of this entry
*/
String getId();
/* Returns the type ID of this entry */
String getClassId();
/* Returns the type of the entry */
String getType();
/* These are key-value pairs for serialization. These are single-valued.
* Serializable classes are: String, Number and Boolean */
Map<String, Serializable> getValues();
/* These are references to other objects in the graph.
* Each key may have one or more references */
Map<String, List<String>> getReferences();
}
@@ -0,0 +1,19 @@
package ch.eth.sis.rocrate.facade;
import java.util.List;
public interface IPropertyType
{
/* Returns the ID of this property type */
String getId();
/* Return possible values for the subject of this property type */
List<String> getDomain();
/* Return possible values for the object of this property type */
List<String> getRange();
/* Returns the ontological annotations of this property type */
List<String> getOntologicalAnnotations();
}
@@ -0,0 +1,35 @@
package ch.eth.sis.rocrate.facade;
import java.util.List;
public interface ISchemaFacade
{
/* Adds a single class */
void addType(IType rdfsClass);
/** Retrieves all Classes */
List<IType> getTypes();
/* Get a single type by its ID */
IType getTypes(String id);
/* Adds a single property */
void addPropertyType(IPropertyType property);
/* Get all Properties */
List<IPropertyType> getPropertyTypes();
/* Gets a single property by its ID. */
IPropertyType getPropertyType(String id);
/* Add a single metadata entry */
void addEntry(IMetadataEntry entry);
/* Get a single metadata entry by its ID */
IMetadataEntry getEntry(String id);
/* Get all metadata entities */
List<IMetadataEntry> getEntries(String rdfsClassId);
}
@@ -0,0 +1,18 @@
package ch.eth.sis.rocrate.facade;
import java.util.List;
public interface IType
{
/* Returns the ID of this type */
String getId();
/* Returns IDs of the types this type inherits from */
List<String> getSubClassOf();
/* Returns the ontological annotations of this type */
List<String> getOntologicalAnnotations();
}
@@ -0,0 +1,32 @@
package ch.eth.sis.rocrate.facade;
/**
* List of primitives as supported by xsd
* https://www.ibm.com/docs/en/jfsm/1.1.2.1?topic=queries-xsd-data-types
*/
public enum LiteralType implements IDataType
{
BOOLEAN("xsd:boolean"),
INTEGER("xsd:integer"),
DOUBLE("xsd:double"),
DECIMAL("xsd:decimal"),
FLOAT("xsd:float"),
DATETIME("xsd:dateTime"),
STRING("xsd:string"),
XML_LITERAL("rdf:XMLLiteral");
final String typeName;
LiteralType(String typeName)
{
this.typeName = typeName;
}
@Override
public String getTypeName()
{
return typeName;
}
}
@@ -0,0 +1,103 @@
package ch.eth.sis.rocrate.facade;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class MetadataEntry implements IMetadataEntry
{
String id;
String type;
Map<String, Serializable> props;
Map<String, List<String>> references;
List<String> childrenIdentifiers = new ArrayList<>();
List<String> parentIdentifiers = new ArrayList<>();
public MetadataEntry()
{
}
public MetadataEntry(String id, String type, Map<String, Serializable> props,
Map<String, List<String>> references)
{
this.id = id;
this.type = type;
this.props = props;
this.references = references;
}
public String getId()
{
return id;
}
@Override
public String getClassId()
{
return type;
}
@Override
public Map<String, Serializable> getValues()
{
return props;
}
@Override
public Map<String, List<String>> getReferences()
{
return references;
}
public void setId(String id)
{
this.id = id;
}
@Override
public String getType()
{
return type;
}
public void setType(String type)
{
this.type = type;
}
public void addChildIdentifier(String a)
{
childrenIdentifiers.add(a);
}
public void addParentIdentifier(String a)
{
parentIdentifiers.add(a);
}
public List<String> getChildrenIdentifiers()
{
return childrenIdentifiers;
}
public List<String> getParentIdentifiers()
{
return parentIdentifiers;
}
public void setProps(Map<String, Serializable> props)
{
this.props = props;
}
public void setReferences(Map<String, List<String>> references)
{
this.references = references;
}
}
@@ -0,0 +1,86 @@
package ch.eth.sis.rocrate.facade;
import java.util.ArrayList;
import java.util.List;
public class RdfsClass implements IType
{
String id;
String type;
List<String> subClassOf;
List<String> ontologicalAnnotations;
List<TypeProperty> rdfsProperties;
public RdfsClass()
{
this.subClassOf = new ArrayList<>();
this.ontologicalAnnotations = new ArrayList<>();
this.rdfsProperties = new ArrayList<>();
}
public String getId()
{
return id;
}
@Override
public List<String> getSubClassOf()
{
return subClassOf;
}
@Override
public List<String> getOntologicalAnnotations()
{
return ontologicalAnnotations;
}
/**
* This is a convenience method for adding a property to a class.
*
*/
public void addProperty(TypeProperty rdfsProperty)
{
List<String> domainIncludes = rdfsProperty.getDomainIncludes();
if (domainIncludes == null)
{
domainIncludes = new ArrayList<>();
rdfsProperty.setDomainIncludes(domainIncludes);
}
if (id == null)
{
throw new IllegalArgumentException("Class id is null");
}
domainIncludes.add(id);
}
public void setId(String id)
{
this.id = id;
}
public String getType()
{
return "rdfs:Class";
}
public void setType(String type)
{
this.type = type;
}
public void setSubClassOf(List<String> subClassOf)
{
this.subClassOf = subClassOf;
}
public void setOntologicalAnnotations(List<String> ontologicalAnnotations)
{
this.ontologicalAnnotations = ontologicalAnnotations;
}
}
@@ -0,0 +1,81 @@
package ch.eth.sis.rocrate.facade;
import java.util.ArrayList;
import java.util.List;
public class TypeProperty implements IPropertyType
{
List<String> domainIncludes;
List<String> rangeIncludes;
String id;
List<String> ontologicalAnnotations = new ArrayList<>();
public List<String> getDomainIncludes()
{
return domainIncludes;
}
public void setDomainIncludes(List<String> domainIncludes)
{
this.domainIncludes = domainIncludes;
}
public void setRangeIncludes(List<String> rangeIncludes)
{
this.rangeIncludes = rangeIncludes;
}
public String getId()
{
return id;
}
@Override
public List<String> getDomain()
{
return getDomainIncludes();
}
@Override
public List<String> getRange()
{
return rangeIncludes;
}
@Override
public List<String> getOntologicalAnnotations()
{
return ontologicalAnnotations;
}
public void setId(String id)
{
this.id = id;
}
public void setOntologicalAnnotations(List<String> ontologicalAnnotations)
{
this.ontologicalAnnotations = ontologicalAnnotations;
}
public void setTypes(List<IDataType> types)
{
this.rangeIncludes = new ArrayList<>(types.stream().map(IDataType::getTypeName).toList());
}
public void addType(IDataType type)
{
if (this.rangeIncludes == null)
{
this.rangeIncludes = new ArrayList<>();
}
if (!this.rangeIncludes.contains(type.getTypeName()))
{
this.rangeIncludes.add(type.getTypeName());
}
}
}
+300
View File
@@ -0,0 +1,300 @@
# Profile/Module - RO-Crate Convention to Include Schema and Metadata
**Index:**
- [Version](#version)
- [Definitions](#definitions)
- [Goals](#goals)
- [Technologies and Usage](#technologies-and-usage)
- [Schema Representation](#schema-representation)
- [RDFS Class](#rdfs-class)
- [RDFS Property](#rdfs-class)
- [Metadata Representation](#metadata-representation)
- [RDF Metadata Entry](#rdf-metadata-entry)
- [Reference Examples](#reference-examples-for-both-schema-and-entries)
- [API](#api)
- [Schema Representation DTOs](#schema-representation-dtos)
- [Metadata Representation DTOs](#metadata-representation-dtos)
- [Additional RO-Crate API Methods](#additional-ro-crate-api-methods)
- [API Reference Implementation in Java](#api-reference-implementation-in-java)
- [API Reference Examples in Java](#api-reference-examples-in-java)
- [Ongoing Work](#ongoing-work)
- [Possible Future Directions](#possible-future-directions)
- [People](#people)
# Version
0.1.0, initial version, compatible with RO-Crate 1.1
# Definitions
We use the following definitions in our proposal.
- Schema: A logical design that defines the structure, organization and relationship between data.
- Metadata: data of a database adhering to the schema.
- Ontology: A set of concepts and the relationships between these concepts.
# Goals
This proposal SHOULD allow the means to exchange a database schema and database contents in a
standardized way.
As consequence, Integrations SHOULD NOT need to parse individual files in non-standardized formats
anymore to obtain such information but MAY use the Ro-Crate API for such purpose.
Since the goal is that multiple established systems can adhere to it, this poses the
additional problem that are multiple schemas in use for similar concepts.
To address this, we propose a way to annotate our schemas with ontological information.
The ontologies allow identification of shared concepts.
Knowing which concepts are shared allows easier integration for different schemas.
Establishing such a format for interoperability would also benefit independent interoperability
efforts, as they would be available for reuse in other interoperability projects.
This specification is made to be usable in Ro-Crate 1.1, as such:
- It SHOULD NOT add new keywords.
- It SHOULD establish a convention that can be used by the RO-Crate API to read/write the information.
# Technologies and Usage
- [RDF](https://www.w3.org/RDF/): Resource Description Framework is a specification developed by the
World Wide Web
Consortium (W3C) to provide a framework for representing and exchanging data on the web in a
structured way. RDF allows information to be described in terms of subject-predicate-object
triples, which form a graph of interconnected data. RDF can be serialized in different formats,
including JSON-LD as used by RO-Crate.
- [RDFS](https://www.w3.org/TR/rdf-schema/): Resource Description Framework Schema is a
specification developed by the World Wide Web Consortium (W3C) that extends RDF (Resource
Description Framework). RDFS provides a way to define the structure and relationships of RDF data,
allowing for the creation of vocabularies and the specification of classes, properties, and
hierarchies in an RDF dataset.
- [OWL](https://www.w3.org/OWL/): Web Ontology Language is a formal language used to define and
represent ontologies on the web.
- [XSD](https://www.w3.org/TR/xmlschema11-1/): XML Schema Definition is a language used to define
the structure, content, and constraints of XML documents. It will be used in this specification to
express primitive type.
## Schema Representation
Because the schema is graph-based this can be easily integrated into the RO-Crate graph.
The schema could also be included in a separate file in a future version of this specification.
Ontologies are added using OWL's `equivalentClass` and `equivalentProperty` properties.
What are the advantages of this?
- the format is backward compatible
- this only uses features that RO-Crate already provides, no additional keywords are required
- Common format for export that prevents `n * (n - 1)` integration situation
- Thorough description of metadata, better automated checking and read-in
**Formal description:**
RO-Crate MUST include a graph description of the schema.
This is expressed using 2 types:
- RDFS Class
- RDFS Property
### RDFS Class
Based on RDFS classes, these can be used as object and subjects of triples.
| Type/Property | Required? | Description |
|---------------------|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------|
| @id | MUST | ID of the entry |
| @type | MUST | Is `rdfs:Class` |
| owl:equivalentClass | MAY | Ontological annotation https://www.w3.org/TR/owl-ref/#equivalentClass-def |
| rdfs:subClassOf | MUST | Used to indicate inheritance. Each entry has to inherit from something, this can be a base type. https://www.w3.org/TR/rdf-schema/#ch_subclassof |
### RDFS Property
RDFS Properties, these represent predicates in triples.
They also specify, which classes they can interact with.
| Type/Property | Required? | Description |
|------------------------|-----------|----------------------------------------------------------------------------|
| @id | MUST | ID of the entry |
| @type | MUST | Is `rdfs:Property` |
| owl:equivalentProperty | MAY | Ontological annotation https://www.w3.org/TR/owl-ref/#equivalentClass-def |
| schema:domainIncludes | MUST | Describes the possible types of the subject. This can be one or many. |
| schema:rangeIncludes | MUST | Describes the possible types of the object. This can be one or many. |
## Metadata Representation
**Formal description:**
RO-Crate MUST include a graph description of the metadata entries.
This is expressed using 1 type:
- Metadata Entry
### RDF Metadata Entry
A metadata entry, described by a RDFS class.
| Type/Property | Required? | Description |
|---------------|-----------|-----------------------------------------|
| @id | MUST | ID of the entry |
| @type | MUST | Type of the entry, MUST be a RDFS Class |
Further properties are included as specified in the RDFS description as fields.
# Reference Examples for both Schema and Entries
We created a small example. It can be found under:
`./examples/ro-crate-1.1/ro-crate-metadata/ro-crate-metadata.json.`
This describes the export
of `./examples/reference-openbis-export`.
# API
**Formal description:**
To be general, the API uses a lot of strings. This allows flexibility in the classes being used.
The interfaces are shown using Java since is a statically typed language, but they can be
implemented in most languages,
including Python and Javascript.
## Schema Representation DTOs
```Java
/* Represents a class, if we are talking about a schema, it is closely related with the definition of a table or type */
interface IType
{
/* Returns the ID of this type */
String getId();
/* Returns IDs of the types this type inherits from */
List<String> getSubClassOf();
/* Returns the ontological annotations of this type */
List<String> getOntologicalAnnotations();
}
/* Represents a property in a graph, if we are talking about a schema, is closely related with a table column or type property */
interface IPropertyType
{
/* Returns the ID of this property type */
String getId();
/* Return possible values for the subject of this property type */
List<String> getDomain();
/* Return possible values for the object of this property type */
List<String> getRange();
/* Returns the ontological annotations of this property type */
List<String> getOntologicalAnnotations();
}
```
## Metadata Representation DTOs
```Java
/* Represents a metadata entity. It is described */
interface IMetadataEntry
{
/**
* Returns the ID of this entry
*/
String getId();
/* Returns the type ID of this entry */
String getClassId();
/* These are key-value pairs for serialization. These are single-valued.
* Serializable classes are: String, Number and Boolean */
Map<String, Serializable> getValues();
/* These are references to other objects in the graph.
* Each key may have one or more references */
Map<String, List<String>> getReferences();
}
```
## Additional RO-Crate API Methods
```Java
/* The API to program against, this wraps around existing RO-Crate APIs. */
interface ISchemaFacade
{
/* Adds a single class */
void addType(IType rdfsClass);
/** Retrieves all Classes */
List<IType> getTypes();
/* Get a single type by its ID */
IType getTypes(String id);
/* Adds a single property */
void addPropertyType(IPropertyType property);
/* Get all Properties */
List<IPropertyType> getPropertyTypes();
/* Gets a single property by its ID. */
IPropertyType getPropertyType(String id);
/* Add a single metadata entry */
void addEntry(IMetadataEntry entry);
/* Get a single metadata entry by its ID */
IMetadataEntry getEntry(String id);
/* Get all metadata entities */
List<IMetadataEntry> getEntries(String rdfsClassId);
}
```
# API Reference Implementation in Java
A working implementation of the API for Java (source and compiled) can be found
under: `./lib/src`.
A compiled jar can be found under: `./lib/java/bin`.
The dependencies are specified in the module's `build.gradle`
file: `./lib/java/src/build.gradle`.
# API Reference Examples in Java
Working examples of the API in java to read and write can be found
at: `./`, specifically the class
files
- `./lib/java/src/java/ch/eth/sis/rocrate/example/ReadExample.java`
- `./lib/java/src/java/ch/eth/sis/rocrate/example/WriteExample.java`
# Ongoing Work
- Adding complex data types
- Using `rdfs:Label` to indicate the original name of a property (this could also help in resolving
properties with the same name)
- Validation of data types expressed in the schema, e.g. enforcing ISO 8601 for dates
- Bundling ontologies in the RO-Crate
- Find a way of specifying other data formats
# Possible Future Directions
- We would like to store the schema and metadata information in separate files and indicate the
format of the file in `ro-crate-metadata.json`
- Other serialization formats could be supported when using separate files
- Adding methods for deleting to facade to have all CRUD operations
# People
- Andreas Meier (andreas.meier@ethz.ch)
- Juan Fuentes (juan.fuentes@id.ethz.ch)
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+74
View File
@@ -0,0 +1,74 @@
plugins {
id 'java'
id 'application'
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
tasks.withType(JavaCompile) {
options.compilerArgs << '-parameters'
}
repositories {
ivy {
ivyPattern "https://sissource.ethz.ch/openbis/openbis-public/openbis-ivy/-/raw/main/[organisation]/[module]/[revision]/ivy.xml"
artifactPattern "https://sissource.ethz.ch/openbis/openbis-public/openbis-ivy/-/raw/main/[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]"
}
mavenCentral()
}
//'openbis:openbis-v3-api-batteries-included:6.5.0',
//files('libs/openBIS-API-V3-batteries-included-SNAPSHOT-r1718006152.jar'),
dependencies {
implementation 'com.fasterxml.jackson.core:jackson-core'
implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation 'org.slf4j:slf4j-api:2.0.16'
implementation 'edu.kit.datamanager:ro-crate-java:2.0.1'
testImplementation 'junit:junit:4.13.1'
testImplementation('jmock:jmock:2.5.1')
}
configurations.configureEach {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
// https://docs.gradle.org/current/userguide/resolution_rules.html
if (details.requested.group == 'com.fasterxml.jackson.core' && details.requested.name == 'jackson-databind') {
details.useVersion '2.18.0'
}
if (details.requested.group == 'com.fasterxml.jackson.core' && details.requested.name == 'jackson-core') {
details.useVersion '2.18.0'
}
if (details.requested.group == 'org.slf4j') {
details.useVersion '2.0.16'
}
}
}
tasks.register('buildRdfTool', Jar) {
dependsOn tasks.build
duplicatesStrategy 'include'
archiveBaseName.set('lib-rdf-tool')
includeEmptyDirs = false
manifest {
attributes(
'Main-Class': 'ch.ethz.sis.rdf.main.RDFCommandLine'
)
}
from(zipTree(tasks.jar.outputs.files.singleFile)) {
include '**/*'
}
from(configurations.runtimeClasspath.collect { zipTree(it) }) {
include '**/*'
exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA'
}
}
@@ -0,0 +1,566 @@
package ch.eth.sis.rocrate;
import ch.eth.sis.rocrate.facade.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import edu.kit.datamanager.ro_crate.RoCrate;
import edu.kit.datamanager.ro_crate.entities.data.DataEntity;
import java.io.Serializable;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class SchemaFacade implements ISchemaFacade
{
private final static String RDFS_CLASS = "rdfs:Class";
private final static String RDFS_PROPERTY = "rdfs:Property";
public static final String EQUIVALENT_CLASS = "owl:equivalentClass";
public static final String EQUIVALENT_CONCEPT = "owl:equivalentProperty";
public static final String TYPE_RESTRICTION = "owl:restriction";
String rangeIdentifier = "schema:rangeIncludes";
String domainIdentifier = "schema:domainIncludes";
public static final String OWL_MIN_CARDINALITY = "owl:minCardinality";
public static final String OWL_MAX_CARDINALITY = "owl:maxCardinality";
public static final String OWL_RESTRICTION = "owl:restriction";
public static final String ON_PROPERTY = "owl:onProperty";
public static final String RDFS_LABEL = "rdfs:label";
public static final String RDFS_COMMENT = "rdfs:comment";
Pattern p;
String localPrefix = ":";
private Map<String, IType> types;
private Map<String, IPropertyType> propertyTypes;
private Map<String, IMetadataEntry> metadataEntries;
private final RoCrate crate;
@Override
public RoCrate getCrate()
{
return crate;
}
public SchemaFacade(String name, String description, String dateString,
String licenseIdentifier, Map<String, String> context)
{
RoCrate.RoCrateBuilder roCrateBuilder =
new RoCrate.RoCrateBuilder(name, description, dateString,
licenseIdentifier);
roCrateBuilder.addValuePairToContext("schema",
"https://www.w3.org/TR/rdf-schema");
roCrateBuilder.addValuePairToContext("owl",
"https://www.w3.org/TR/owl-ref");
for (Map.Entry<String, String> keyVal : context.entrySet()
)
{
roCrateBuilder.addValuePairToContext(keyVal.getKey(), keyVal.getValue());
}
this.crate = roCrateBuilder.build();
this.types = new LinkedHashMap<>();
this.propertyTypes = new LinkedHashMap<>();
this.metadataEntries = new LinkedHashMap<>();
}
public SchemaFacade(RoCrate crate)
{
this.crate = crate;
this.types = new LinkedHashMap<>();
this.propertyTypes = new LinkedHashMap<>();
this.metadataEntries = new LinkedHashMap<>();
}
public static SchemaFacade of(RoCrate crate) throws JsonProcessingException
{
SchemaFacade schemaFacade = new SchemaFacade(crate);
schemaFacade.parseEntities();
return schemaFacade;
}
@Override
public void addType(IType rdfsClass)
{
DataEntity.DataEntityBuilder builder = new DataEntity.DataEntityBuilder();
builder.addProperty("@id", rdfsClass.getId());
builder.addProperty("@type", RDFS_CLASS);
builder.addProperty(RDFS_LABEL, rdfsClass.getLabel());
builder.addProperty(RDFS_COMMENT, rdfsClass.getComment());
for (IRestriction restriction : rdfsClass.getResstrictions())
{
DataEntity.DataEntityBuilder restrictionBuilder = new DataEntity.DataEntityBuilder();
restrictionBuilder.addProperty("@id", restriction.getId());
restrictionBuilder.addProperty("@type", TYPE_RESTRICTION);
restrictionBuilder.addIdProperty(ON_PROPERTY, restriction.getPropertyType().getId());
restrictionBuilder.addProperty(OWL_MIN_CARDINALITY, restriction.getMinCardinality());
restrictionBuilder.addProperty(OWL_MAX_CARDINALITY, restriction.getMaxCardinality());
builder.addIdProperty(OWL_RESTRICTION, restriction.getId());
crate.addDataEntity(restrictionBuilder.build());
}
rdfsClass.getSubClassOf().forEach(x -> builder.addIdProperty("rdfs:subClassOf", x));
this.types.put(rdfsClass.getId(), rdfsClass);
DataEntity entity = builder.build();
entity.addIdListProperties(EQUIVALENT_CLASS, rdfsClass.getOntologicalAnnotations());
crate.addDataEntity(entity);
}
@Override
public List<IType> getTypes()
{
return this.types.values().stream().toList();
}
@Override
public IType getTypes(String id)
{
return this.types.get(id);
}
@Override
public void addPropertyType(IPropertyType rdfsProperty)
{
DataEntity.DataEntityBuilder builder = new DataEntity.DataEntityBuilder();
builder.setId(rdfsProperty.getId());
builder.addProperty("@type", RDFS_PROPERTY);
builder.addProperty(RDFS_LABEL, rdfsProperty.getLabel());
builder.addProperty(RDFS_COMMENT, rdfsProperty.getComment());
var stuff = builder.build();
stuff.addIdListProperties("schema:rangeIncludes",
rdfsProperty.getRange());
stuff.addIdListProperties("schema:domainIncludes",
rdfsProperty.getDomain().stream().map(x -> x.getId()).collect(Collectors.toList()));
stuff.addIdListProperties(EQUIVALENT_CONCEPT,
rdfsProperty.getOntologicalAnnotations());
crate.addDataEntity(stuff);
propertyTypes.put(rdfsProperty.getId(), rdfsProperty);
}
@Override
public void addRestriction(IRestriction restriction)
{
}
@Override
public List<IPropertyType> getPropertyTypes()
{
return propertyTypes.values().stream().toList();
}
@Override
public IPropertyType getPropertyType(String id)
{
return propertyTypes.get(id);
}
@Override
public void addEntry(IMetadataEntry metaDataEntry)
{
DataEntity.DataEntityBuilder builder = new DataEntity.DataEntityBuilder();
builder.setId(metaDataEntry.getId());
for (String type : metaDataEntry.getTypes())
{
builder.addType(type);
}
ObjectMapper objectMapper = new ObjectMapper();
metaDataEntry.getValues().forEach((s, o) -> {
if (o instanceof Double)
{
builder.addProperty(s, (Double) o);
} else if (o instanceof Integer)
{
builder.addProperty(s, (Integer) o);
} else if (o instanceof Boolean)
{
builder.addProperty(s, (Boolean) o);
} else if (o instanceof String)
{
builder.addProperty(s, o.toString());
} else if (o == null)
{
builder.addProperty(s, objectMapper.nullNode());
}
});
DataEntity dataEntity = builder.build();
metaDataEntry.getReferences().forEach(dataEntity::addIdListProperties);
crate.addDataEntity(dataEntity);
}
@Override
public IMetadataEntry getEntry(String id)
{
return metadataEntries.get(id);
}
@Override
public List<IMetadataEntry> getEntries(String rdfsClassId)
{
return metadataEntries.values().stream()
.filter(x -> matchClasses(resolvePrefixSingleValue(rdfsClassId), x))
.toList();
}
@Override
public List<IRestriction> getRestrictions()
{
return null;
}
private boolean matchClasses(String queryClassId, IMetadataEntry entry)
{
if (entry.getTypes().stream().anyMatch(x -> x.equals(queryClassId)))
{
return true;
}
return entry.getTypes().stream()
.map(x -> p.matcher(x))
.map(x -> x.replaceAll("_:"))
.anyMatch(x -> x.equals(queryClassId));
}
private void parseEntities() throws JsonProcessingException
{
localPrefix = getLocalPrefix(crate.getJsonMetadata());
Map<String, String> keyValuePairs = getKeyValPairsFromMetadata(crate.getJsonMetadata());
for (var keyValPair : keyValuePairs.entrySet())
{
if (keyValPair.getValue().equals("http://schema.org/rangeIncludes"))
{
rangeIdentifier = keyValPair.getKey();
}
if (keyValPair.getValue().equals("http://schema.org/domainIncludes"))
{
domainIdentifier = keyValPair.getKey();
}
}
Map<String, IPropertyType> properties = new LinkedHashMap<>();
Map<String, IType> classes = new LinkedHashMap<>();
Map<String, IMetadataEntry> entries = new LinkedHashMap<>();
Map<String, Type> restrictionToTypeId = new LinkedHashMap<>();
for (DataEntity entity : crate.getAllDataEntities())
{
String type = entity
.getProperty("@type").asText();
String id =
entity.getProperty("@id")
.asText();
switch (type)
{
case "rdfs:Class" ->
{
Type myType = new Type();
myType.setSubClassOf(parseMultiValued(entity, "rdfs:subClassOf"));
myType.setOntologicalAnnotations(
parseMultiValued(entity, EQUIVALENT_CLASS));
myType.setId(resolvePrefixSingleValue(id));
classes.put(resolvePrefixSingleValue(id), myType);
parseMultiValued(entity, OWL_RESTRICTION).forEach(
x -> restrictionToTypeId.put(x, myType));
}
}
}
for (DataEntity entity : crate.getAllDataEntities())
{
String type = entity
.getProperty("@type").asText();
String id =
entity.getProperty("@id")
.asText();
switch (type)
{
case "rdfs:Property" ->
{
PropertyType rdfsProperty = new PropertyType();
rdfsProperty.setId(resolvePrefixSingleValue(id));
rdfsProperty.setOntologicalAnnotations(
parseMultiValued(entity, EQUIVALENT_CONCEPT));
List<String> rawRange = parseMultiValued(entity, rangeIdentifier);
List<IDataType> dataTypes = rawRange.stream()
.filter(LiteralType::isLiteralType)
.map(LiteralType::getByTypeName)
.filter(Objects::nonNull)
.collect(Collectors.toList());
List<IType> types = rawRange.stream()
.filter(x -> !LiteralType.isLiteralType(x))
.map(this::resolvePrefixSingleValue)
.map(classes::get)
.collect(Collectors.toList());
dataTypes.stream().forEach(rdfsProperty::addDataType);
types.forEach(rdfsProperty::addType);
rdfsProperty.setDomainIncludes(
parseMultiValued(entity, domainIdentifier).stream()
.map(x -> resolvePrefixSingleValue(x))
.map(classes::get).collect(
Collectors.toList()));
properties.put(resolvePrefixSingleValue(id), rdfsProperty);
}
}
}
for (DataEntity entity : crate.getAllDataEntities())
{
String type = entity.getProperty("@type").asText();
String id =
entity.getProperty("@id")
.asText();
if (type.equals(OWL_RESTRICTION))
{
String onProperty = parseMultiValued(entity, ON_PROPERTY).get(0);
int minCardinality =
entity.getProperty(OWL_MIN_CARDINALITY).numberValue().intValue();
int maxCardinality =
entity.getProperty(OWL_MAX_CARDINALITY).numberValue().intValue();
Restriction restriction =
new Restriction(id, properties.get(onProperty), minCardinality,
maxCardinality);
restrictionToTypeId.get(id).addRestriction(restriction);
}
}
for (var entity : crate.getAllDataEntities())
{
Set<String> type = parseTypes(entity);
String id =
entity.getProperty("@id")
.asText();
if (!doesTypeExist(type, classes, localPrefix))
{
continue;
}
Map<String, Serializable> entryProperties = new LinkedHashMap<>();
MetadataEntry entry = new MetadataEntry();
entry.setId(id);
entry.setTypes(resolvePrefix(type));
Map<String, List<String>> references = new LinkedHashMap<>();
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Serializable> keyVals =
objectMapper.readValue(entity.getProperties().toString(), HashMap.class);
for (Map.Entry<String, Serializable> a : keyVals.entrySet())
{
if (properties.containsKey(a.getKey()))
{
IPropertyType property = properties.get(a.getKey());
if (property.getRange().stream().anyMatch(x -> x.startsWith("xsd:")))
{
entryProperties.put(a.getKey(), a.getValue().toString());
} else
{
List<String> refs = parseMultiValued(entity, a.getKey());
references.put(a.getKey(), refs);
}
}
}
entry.setProps(entryProperties);
entry.setReferences(references);
entries.put(id, entry);
}
System.out.println("Done");
this.types = classes;
this.propertyTypes = properties;
this.metadataEntries = entries;
}
private Set<String> resolvePrefix(Set<String> types)
{
Pattern placeholderPattern = Pattern.compile("^_:");
LinkedHashSet newTypes = new LinkedHashSet();
for (String type : types)
{
newTypes.add(placeholderPattern.matcher(type).replaceAll(localPrefix));
}
return newTypes;
}
private String resolvePrefixSingleValue(String type)
{
Pattern placeholderPattern = Pattern.compile("^_:");
return placeholderPattern.matcher(type).replaceAll(localPrefix);
}
private List<String> parseMultiValued(DataEntity dataEntity, String key)
{
JsonNode node = dataEntity.getProperty(key);
if (node instanceof ObjectNode)
{
return List.of(node.get("@id").textValue());
}
if (node instanceof ArrayNode arrayNode)
{
List<String> accumulator = new ArrayList<>();
arrayNode.elements().forEachRemaining(
x -> accumulator.add(x.get("@id").textValue())
);
return accumulator;
}
return List.of();
}
private Set<String> parseTypes(DataEntity entity)
{
JsonNode typeResult = entity.getProperty("@type");
if (typeResult.isTextual())
{
return Set.of(typeResult.textValue());
}
if (typeResult.isArray())
{
ArrayNode arrayNode = (ArrayNode) typeResult;
Set<String> typeroos = new LinkedHashSet<>();
arrayNode.forEach(x -> typeroos.add(x.textValue()));
return typeroos;
}
throw new RuntimeException("Unknown node type for @type");
}
Map<String, String> getKeyValPairsFromMetadata(String metaDataJson)
throws JsonProcessingException
{
ObjectMapper objectMapper = new ObjectMapper();
LinkedHashMap vals = objectMapper.readValue(metaDataJson, LinkedHashMap.class);
if (vals.get("@context") instanceof LinkedHashMap<?, ?>)
{
return (Map<String, String>) vals.get("@context");
}
if (vals.get("@context") instanceof String)
{
return Map.of();
}
List<Object> nodes = (List<Object>) vals.get("@context");
Map key_vals = (Map) nodes.get(1);
Map<String, String> result = new LinkedHashMap<>();
for (Object a : key_vals.entrySet())
{
Map.Entry b = (Map.Entry) a;
result.put(b.getKey().toString(), b.getValue().toString());
}
return result;
}
String getLocalPrefix(String jsonMetaData) throws JsonProcessingException
{
Map<String, String> keyVals = getKeyValPairsFromMetadata(jsonMetaData);
for (Map.Entry<String, String> entry : keyVals.entrySet())
{
if (entry.getValue().equals("_:"))
{
return entry.getKey() + ":";
}
}
return "";
}
boolean doesTypeExist(Set<String> types, Map<String, IType> classes, String localPrefix)
{
p = Pattern.compile("^" + localPrefix + ":", Pattern.CASE_INSENSITIVE);
boolean somethingFound = false;
for (String type : types)
{
boolean typeFound = false;
Matcher m = p.matcher(type);
if (classes.containsKey(type))
{
typeFound = true;
}
if (classes.containsKey(m.replaceAll("_:")))
{
typeFound = true;
}
if (!typeFound)
{
System.out.println("Type " + type + " does not seem to be part of the schema");
}
somethingFound = somethingFound || typeFound;
}
return somethingFound;
}
}
@@ -0,0 +1,38 @@
package ch.eth.sis.rocrate.example;
import ch.eth.sis.rocrate.SchemaFacade;
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;
public class ReadExample
{
/**
* This reads an RO-Crate with schema information and prints out
* If you need a compatible RO-Crate, run WriteExample.java first.
* Takes one optional command line argument for an output path, if not provided, it will read from
* ./out
* @param args
* @throws JsonProcessingException
*/
public static void main(String[] args) throws JsonProcessingException
{
String path = args.length >= 1 ? args[0] : "out";
RoCrateReader roCrateFolderReader = new RoCrateReader(new FolderReader());
RoCrate crate = roCrateFolderReader.readCrate(path);
SchemaFacade schemaFacade = SchemaFacade.of(crate);
schemaFacade.getTypes().forEach(
x -> System.out.println("RDFS Class " + x.getId())
);
schemaFacade.getPropertyTypes().forEach(
x -> System.out.println("RDFS Property " + x.getId())
);
schemaFacade.getEntries(schemaFacade.getTypes().get(0).getId()).forEach(
x -> System.out.println("Metadata entry " + x.getId())
);
}
}
@@ -0,0 +1,108 @@
package ch.eth.sis.rocrate.example;
import ch.eth.sis.rocrate.SchemaFacade;
import ch.eth.sis.rocrate.facade.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import edu.kit.datamanager.ro_crate.writer.FolderWriter;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class WriteExample
{
/**
* This is a small example that adds one type for a textual resource with two properties. One
* of the properties is a literal, date, while the other references the creator. The creator
* type has its own properties. Some of the properties have ontological annotations to clarify
* their meanings.
* Takes one optional command line argument for an output path, if not provided, it will write to
* ./out
*
* @param args
* @throws JsonProcessingException
*/
public static void main(String[] args) throws JsonProcessingException
{
ISchemaFacade schemaFacade =
new SchemaFacade("name", "description", "2024-12-04T07:53:11Z", "licenceIdentifier",
Map.of());
{
Type type = new Type();
type.setId("TextResource");
type.setSubClassOf(List.of("https://schema.org/Thing"));
type.setOntologicalAnnotations(
List.of("https://www.dublincore.org/specifications/dublin-core/dcmi-terms/dcmitype/Text/"));
schemaFacade.addType(type);
Type creatorType = new Type();
creatorType.setId("Creator");
creatorType.setSubClassOf(List.of("https://schema.org/Thing"));
creatorType.setOntologicalAnnotations(
List.of("https://www.dublincore.org/specifications/dublin-core/dcmi-terms/terms/creator//"));
schemaFacade.addType(type);
schemaFacade.addType(creatorType);
{
}
PropertyType property = new PropertyType();
property.setId("hasDateSubmitted");
property.addDataType(LiteralType.DATETIME);
property.setOntologicalAnnotations(
List.of("https://www.dublincore.org/specifications/dublin-core/dcmi-terms/terms/dateSubmitted/"));
type.addProperty(property);
PropertyType propertyCreator = new PropertyType();
propertyCreator.setId("hasCreator");
propertyCreator.addType(creatorType);
type.addProperty(propertyCreator);
PropertyType name = new PropertyType();
name.setId("hasName");
name.addDataType(LiteralType.STRING);
creatorType.addProperty(name);
PropertyType identifier = new PropertyType();
identifier.setId("hasIdentifier");
identifier.addDataType(LiteralType.STRING);
identifier.setOntologicalAnnotations(
List.of("https://www.dublincore.org/specifications/dublin-core/dcmi-terms/elements11/identifier/"));
creatorType.addProperty(identifier);
schemaFacade.addPropertyType(property);
schemaFacade.addPropertyType(propertyCreator);
schemaFacade.addPropertyType(identifier);
schemaFacade.addPropertyType(name);
String creatorId = "creator1";
IMetadataEntry creatorEntry = new MetadataEntry(creatorId, Set.of(creatorType.getId()),
Map.of("hasName", "John Author", "hasIdentifier",
"https://orcid.org/0000-0000-0000-0000"), Map.of());
IMetadataEntry metadataEntry =
new MetadataEntry("TextResource1", Set.of("TextResource"),
Map.of("hasDate", "2025-01-21T07:12:20Z"),
Map.of("hasCreator", List.of(creatorId)));
schemaFacade.addEntry(metadataEntry);
schemaFacade.addEntry(creatorEntry);
}
String path = args.length >= 1 ? args[0] : "out";
FolderWriter folderWriter = new FolderWriter();
folderWriter.save(schemaFacade.getCrate(), path);
}
}
@@ -0,0 +1,21 @@
package ch.eth.sis.rocrate.facade;
public interface IDataType
{
String getTypeName();
static IDataType getArray(LiteralType literalType)
{ //TODO static IDataType getArray(LiteralType literalType)
throw new UnsupportedOperationException("Feature incomplete. Contact assistance.");
}
static IDataType getEnumerationf(String... values)
{ //TODO static IDataType getEnumerationf(String... values)
throw new UnsupportedOperationException("Feature incomplete. Contact assistance.");
}
static IDataType getCustomType(LiteralType basicType, String pattern)
{ //TODO static IDataType getCustomType(LiteralType basicType, String pattern)
throw new UnsupportedOperationException("Feature incomplete. Contact assistance.");
}
}
@@ -0,0 +1,30 @@
package ch.eth.sis.rocrate.facade;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
public interface IMetadataEntry
{
/**
* Returns the ID of this entry
*/
String getId();
/* Returns the type ID of this entry */
String getClassId();
/* Returns the types of the entry */
Set<String> getTypes();
/* These are key-value pairs for serialization. These are single-valued.
* Serializable classes are: String, Number and Boolean */
Map<String, Serializable> getValues();
/* These are references to other objects in the graph.
* Each key may have one or more references */
Map<String, List<String>> getReferences();
}
@@ -0,0 +1,25 @@
package ch.eth.sis.rocrate.facade;
import java.util.List;
public interface IPropertyType
{
/* Returns the ID of this property type */
String getId();
/* Return possible values for the subject of this property type */
List<IType> getDomain();
/* Return possible values for the object of this property type */
List<String> getRange();
/* Returns the ontological annotations of this property type */
List<String> getOntologicalAnnotations();
/* Returns a human-readable description of this type */
String getComment();
/* Returns a human-readable label of this type */
String getLabel();
}
@@ -0,0 +1,13 @@
package ch.eth.sis.rocrate.facade;
public interface IRestriction
{
String getId();
IPropertyType getPropertyType();
int getMinCardinality();
int getMaxCardinality();
}
@@ -0,0 +1,45 @@
package ch.eth.sis.rocrate.facade;
import edu.kit.datamanager.ro_crate.RoCrate;
import java.util.List;
public interface ISchemaFacade
{
/* Get the crate being worked on */
RoCrate getCrate();
/* Adds a single class */
void addType(IType rdfsClass);
/** Retrieves all Classes */
List<IType> getTypes();
/* Get a single type by its ID */
IType getTypes(String id);
/* Adds a single property */
void addPropertyType(IPropertyType property);
/* Adds a restriction */
void addRestriction(IRestriction restriction);
/* Get all Properties */
List<IPropertyType> getPropertyTypes();
/* Gets a single property by its ID. */
IPropertyType getPropertyType(String id);
/* Add a single metadata entry */
void addEntry(IMetadataEntry entry);
/* Get a single metadata entry by its ID */
IMetadataEntry getEntry(String id);
/* Get all metadata entities */
List<IMetadataEntry> getEntries(String rdfsClassId);
List<IRestriction> getRestrictions();
}
@@ -0,0 +1,27 @@
package ch.eth.sis.rocrate.facade;
import java.util.List;
public interface IType
{
/* Returns the ID of this type */
String getId();
/* Returns IDs of the types this type inherits from */
List<String> getSubClassOf();
/* Returns the ontological annotations of this type */
List<String> getOntologicalAnnotations();
/* Returns a human-readable description of this type */
String getComment();
/* Returns a human-readable label of this type */
String getLabel();
/* Get Restrictions placed on the properties of this type */
List<IRestriction> getResstrictions();
}
@@ -0,0 +1,58 @@
package ch.eth.sis.rocrate.facade;
/**
* List of primitives as supported by xsd
* https://www.ibm.com/docs/en/jfsm/1.1.2.1?topic=queries-xsd-data-types
*/
public enum LiteralType implements IDataType
{
BOOLEAN("xsd:boolean"),
INTEGER("xsd:integer"),
DOUBLE("xsd:double"),
DECIMAL("xsd:decimal"),
FLOAT("xsd:float"),
DATETIME("xsd:dateTime"),
STRING("xsd:string"),
XML_LITERAL("rdf:XMLLiteral");
final String typeName;
LiteralType(String typeName)
{
this.typeName = typeName;
}
@Override
public String getTypeName()
{
return typeName;
}
public static boolean isLiteralType(String typeName)
{
for (LiteralType literalType : LiteralType.values())
{
if (typeName.equals(literalType.getTypeName()))
{
return true;
}
}
return false;
}
public static LiteralType getByTypeName(String typeName)
{
for (LiteralType literalType : LiteralType.values())
{
if (typeName.equals(literalType.getTypeName()))
{
return literalType;
}
}
throw new IllegalArgumentException("Unknown literal type: " + typeName);
}
}
@@ -0,0 +1,118 @@
package ch.eth.sis.rocrate.facade;
import java.io.Serializable;
import java.util.*;
public class MetadataEntry implements IMetadataEntry
{
String id;
Set<String> types;
Map<String, Serializable> props;
Map<String, List<String>> references;
List<String> childrenIdentifiers = new ArrayList<>();
List<String> parentIdentifiers = new ArrayList<>();
public MetadataEntry()
{
}
public MetadataEntry(String id, Set<String> types, Map<String, Serializable> props,
Map<String, List<String>> references)
{
this.id = id;
this.types = types;
this.props = props;
this.references = references;
}
public String getId()
{
return id;
}
@Override
public String getClassId()
{
return null;
}
@Override
public Map<String, Serializable> getValues()
{
return props;
}
@Override
public Map<String, List<String>> getReferences()
{
return references;
}
public void setId(String id)
{
this.id = id;
}
@Override
public Set<String> getTypes()
{
return types;
}
public void setTypes(Set<String> types)
{
this.types = types;
}
public void addChildIdentifier(String a)
{
childrenIdentifiers.add(a);
}
public void addParentIdentifier(String a)
{
parentIdentifiers.add(a);
}
public List<String> getChildrenIdentifiers()
{
return childrenIdentifiers;
}
public List<String> getParentIdentifiers()
{
return parentIdentifiers;
}
public void setProps(Map<String, Serializable> props)
{
this.props = props;
}
public void setReferences(Map<String, List<String>> references)
{
this.references = references;
}
@Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
MetadataEntry entry = (MetadataEntry) o;
return Objects.equals(id, entry.id) && Objects.equals(types, entry.types);
}
@Override
public int hashCode()
{
return Objects.hash(id, types);
}
}
@@ -0,0 +1,132 @@
package ch.eth.sis.rocrate.facade;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class PropertyType implements IPropertyType
{
List<IType> domainIncludes;
List<IType> rangeIncludes;
List<IDataType> rangeeIndlucesDataType;
String id;
List<String> ontologicalAnnotations = new ArrayList<>();
String label;
String comment;
public PropertyType()
{
this.rangeIncludes = new ArrayList<>();
this.rangeeIndlucesDataType = new ArrayList<>();
this.ontologicalAnnotations = new ArrayList<>();
}
public List<IType> getDomainIncludes()
{
return domainIncludes;
}
public void setDomainIncludes(List<IType> domainIncludes)
{
this.domainIncludes = domainIncludes;
}
public String getId()
{
return id;
}
@Override
public List<IType> getDomain()
{
return getDomainIncludes();
}
@Override
public List<String> getRange()
{
Stream<String> a = rangeIncludes.stream().map(x -> x.getId());
Stream<String> b = rangeeIndlucesDataType.stream().map(x -> x.getTypeName());
return Stream.concat(a, b).collect(Collectors.toList());
}
@Override
public List<String> getOntologicalAnnotations()
{
return ontologicalAnnotations;
}
@Override
public String getComment()
{
return comment;
}
@Override
public String getLabel()
{
return label;
}
public void setId(String id)
{
this.id = id;
}
public void setOntologicalAnnotations(List<String> ontologicalAnnotations)
{
this.ontologicalAnnotations = ontologicalAnnotations;
}
public void setTypes(List<IDataType> types)
{
this.rangeeIndlucesDataType = new ArrayList<>(types);
}
public void addDataType(IDataType type)
{
if (this.rangeeIndlucesDataType == null)
{
this.rangeeIndlucesDataType = new ArrayList<>();
}
if (!rangeeIndlucesDataType.contains(type))
{
rangeeIndlucesDataType.add(type);
}
}
public void addType(IType type)
{
if (this.rangeIncludes == null)
{
this.rangeIncludes = new ArrayList<>();
}
if (!this.rangeIncludes.contains(type))
{
this.rangeIncludes.add(type);
}
}
public void setLabel(String label)
{
this.label = label;
}
public void setComment(String comment)
{
this.comment = comment;
}
}
@@ -0,0 +1,86 @@
ackage ch.eth.sis.rocrate.facade;
import java.util.ArrayList;
import java.util.List;
public class RdfsClass implements IType
{
String id;
String type;
List<String> subClassOf;
List<String> ontologicalAnnotations;
List<TypeProperty> rdfsProperties;
public RdfsClass()
{
this.subClassOf = new ArrayList<>();
this.ontologicalAnnotations = new ArrayList<>();
this.rdfsProperties = new ArrayList<>();
}
public String getId()
{
return id;
}
@Override
public List<String> getSubClassOf()
{
return subClassOf;
}
@Override
public List<String> getOntologicalAnnotations()
{
return ontologicalAnnotations;
}
/**
* This is a convenience method for adding a property to a class.
*
*/
public void addProperty(TypeProperty rdfsProperty)
{
List<String> domainIncludes = rdfsProperty.getDomainIncludes();
if (domainIncludes == null)
{
domainIncludes = new ArrayList<>();
rdfsProperty.setDomainIncludes(domainIncludes);
}
if (id == null)
{
throw new IllegalArgumentException("Class id is null");
}
domainIncludes.add(id);
}
public void setId(String id)
{
this.id = id;
}
public String getType()
{
return "rdfs:Class";
}
public void setType(String type)
{
this.type = type;
}
public void setSubClassOf(List<String> subClassOf)
{
this.subClassOf = subClassOf;
}
public void setOntologicalAnnotations(List<String> ontologicalAnnotations)
{
this.ontologicalAnnotations = ontologicalAnnotations;
}
}
@@ -0,0 +1,48 @@
package ch.eth.sis.rocrate.facade;
public class Restriction implements IRestriction
{
String id;
IPropertyType propertyType;
int minCardinality;
int maxCardinality;
public Restriction(String id, IPropertyType propertyType, int minCardinality,
int maxCardinality)
{
this.id = id;
this.propertyType = propertyType;
this.minCardinality = minCardinality;
this.maxCardinality = maxCardinality;
}
@Override
public String getId()
{
return id;
}
@Override
public IPropertyType getPropertyType()
{
return propertyType;
}
@Override
public int getMinCardinality()
{
return minCardinality;
}
@Override
public int getMaxCardinality()
{
return maxCardinality;
}
}
@@ -0,0 +1,144 @@
package ch.eth.sis.rocrate.facade;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class Type implements IType
{
String id;
String type;
List<String> subClassOf;
List<String> ontologicalAnnotations;
List<PropertyType> rdfsProperties;
String comment;
String label;
List<IRestriction> restrictions;
public Type()
{
this.subClassOf = new ArrayList<>();
this.ontologicalAnnotations = new ArrayList<>();
this.rdfsProperties = new ArrayList<>();
this.restrictions = new ArrayList<>();
}
public String getId()
{
return id;
}
@Override
public List<String> getSubClassOf()
{
return subClassOf;
}
@Override
public List<String> getOntologicalAnnotations()
{
return ontologicalAnnotations;
}
@Override
public String getComment()
{
return null;
}
@Override
public String getLabel()
{
return null;
}
@Override
public List<IRestriction> getResstrictions()
{
return restrictions;
}
/**
* This is a convenience method for adding a property to a class.
*
*/
public void addProperty(PropertyType rdfsProperty)
{
List<IType> domainIncludes = rdfsProperty.getDomainIncludes();
if (domainIncludes == null)
{
domainIncludes = new ArrayList<>();
rdfsProperty.setDomainIncludes(domainIncludes);
}
if (id == null)
{
throw new IllegalArgumentException("Class id is null");
}
domainIncludes.add(this);
}
public void setId(String id)
{
this.id = id;
}
public String getType()
{
return "rdfs:Class";
}
public void setType(String type)
{
this.type = type;
}
public void setSubClassOf(List<String> subClassOf)
{
this.subClassOf = subClassOf;
}
public void setOntologicalAnnotations(List<String> ontologicalAnnotations)
{
this.ontologicalAnnotations = ontologicalAnnotations;
}
public void setComment(String comment)
{
this.comment = comment;
}
public void setLabel(String label)
{
this.label = label;
}
public void addRestriction(IRestriction restriction)
{
this.restrictions.add(restriction);
}
@Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Type type = (Type) o;
return Objects.equals(id, type.id);
}
@Override
public int hashCode()
{
return Objects.hash(id);
}
}
+409
View File
@@ -0,0 +1,409 @@
# Profile/Module : RO-Crate Interoperability Profile
AKA: Convention to include schemas and metadata inside `ro-crate-metadata.json`
**Index:**
### ro-crate-metadata.json Convention
- [Version](#version)
- [What's new?](#whats-new)
- [Definitions](#definitions)
- [Background](#background)
- [Goals](#goals)
- [Technologies and Usage](#technologies-and-usage)
- [Schema Representation](#schema-representation)
- [RDFS Class](#rdfs-class)
- [RDFS Property](#rdfs-class)
- [Metadata Representation](#metadata-representation)
- [RDF Metadata Entry](#rdf-metadata-entry)
- [Reference Examples](#reference-examples-for-both-schema-and-entries)
### Reference API
- [API](#api)
- [Schema Representation DTOs](#schema-representation-dtos)
- [Metadata Representation DTOs](#metadata-representation-dtos)
- [Additional RO-Crate API Methods](#additional-ro-crate-api-methods)
- [Primitive Data Types](#primitive-data-types)
- [API Reference Implementation in Java](#api-reference-implementation-in-java)
- [API Reference Examples in Java](#api-reference-examples-in-java)
### Organizational Information
- [Ongoing Work](#ongoing-work)
- [Possible Future Directions](#possible-future-directions)
- [People](#people)
# Changelog
### 0.2.0, compatible with RO-Crate 1.1
#### What's new?
- Cardinalities [RDFS Class](#rdfs-class), [OWl Restriction](#owl-restriction)
- Mandatory properties [RDFS Class](#rdfs-class), [OWl Restriction](#owl-restriction)
- Labels [RDFS Property](#rdfs-class), [RDFS Class](#rdfs-class)
- Human-readable comments[RDFS Property](#rdfs-class), [RDFS Class](#rdfs-class)
- Intersection types [RDF Metadata Entry](#rdf-metadata-entry)
- Better description of primitive data types [Primitive Data Types](#primitive-data-types)
- Ranges of properties are now built using this library's IType and LiteralType
- Updated future plans! [Possible Future Directions](#possible-future-directions)
- Background section [Background](#background)
### 0.1.0, compatible with RO-Crate 1.1
- Initial version
# Definitions
We use the following definitions in our proposal.
- Schema: A logical design that defines the structure, organization and relationship between data.
- Metadata: data of a database adhering to the schema.
- Ontology: A set of concepts and the relationships between these concepts.
# Background
This convention has its roots in interoperability projects involving established electronic lab notebooks and data repositories.
For historical reasons, schemas for metadata may differ between systems, even if they cover similar concepts.
# Goals
This proposal SHOULD allow the means to exchange a database schema and database contents in a
standardized way.
As consequence, Integrations SHOULD NOT need to parse individual files in non-standardized formats
anymore to obtain such information but MAY use the Ro-Crate API for such purpose.
Since the goal is that multiple established systems can adhere to it, this poses the
additional problem that are multiple schemas in use for similar concepts.
To address this, we propose a way to annotate our schemas with ontological information.
The ontologies allow identification of shared concepts.
Knowing which concepts are shared allows easier integration for different schemas.
Establishing such a format for interoperability would also benefit independent interoperability
efforts, as they would be available for reuse in other interoperability projects.
This specification is made to be usable in Ro-Crate 1.1, as such:
- It SHOULD NOT add new keywords.
- It SHOULD establish a convention that can be used by the RO-Crate API to read/write the information.
# Technologies and Usage
- [RDF](https://www.w3.org/RDF/): Resource Description Framework is a specification developed by the
World Wide Web
Consortium (W3C) to provide a framework for representing and exchanging data on the web in a
structured way. RDF allows information to be described in terms of subject-predicate-object
triples, which form a graph of interconnected data. RDF can be serialized in different formats,
including JSON-LD as used by RO-Crate.
- [RDFS](https://www.w3.org/TR/rdf-schema/): Resource Description Framework Schema is a
specification developed by the World Wide Web Consortium (W3C) that extends RDF (Resource
Description Framework). RDFS provides a way to define the structure and relationships of RDF data,
allowing for the creation of vocabularies and the specification of classes, properties, and
hierarchies in an RDF dataset.
- [OWL](https://www.w3.org/OWL/): Web Ontology Language is a formal language used to define and
represent ontologies on the web.
- [XSD](https://www.w3.org/TR/xmlschema11-1/): XML Schema Definition is a language used to define
the structure, content, and constraints of XML documents. It will be used in this specification to
express primitive type.
## Schema Representation
Because the schema is graph-based this can be easily integrated into the RO-Crate graph.
The schema could also be included in a separate file in a future version of this specification.
Ontologies are added using OWL's `equivalentClass` and `equivalentProperty` properties.
What are the advantages of this?
- the format is backward compatible
- this only uses features that RO-Crate already provides, no additional keywords are required
- Common format for export that prevents `n * (n - 1)` integration situation
- Thorough description of metadata, better automated checking and read-in
**Formal description:**
RO-Crate MUST include a graph description of the schema.
This is expressed using 2 types:
- RDFS Class
- RDFS Property
### RDFS Class
Based on RDFS classes, these can be used as object and subjects of triples.
| Type/Property | Required? | Description |
|---------------------|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------|
| @id | MUST | ID of the entry |
| @type | MUST | Is `rdfs:Class` |
| owl:equivalentClass | MAY | Ontological annotation https://www.w3.org/TR/owl-ref/#equivalentClass-def |
| rdfs:subClassOf | MUST | Used to indicate inheritance. Each entry has to inherit from something, this can be a base type. https://www.w3.org/TR/rdf-schema/#ch_subclassof |
| rdfs:label | MAY | Label of the class |
| rdfs:comment | MAY | Human-readable description of this class |
| owl:restriction | MAY | OWL restriction, a list of OWL restrictions, see [OWl Restriction](#owl-restriction) |
### OWL Restriction
These represent restrictions on properties. At the moment, they encode cardinalities.
Cardinalities with a max of 0 and a min of 0 can be omitted.
A max cardinality of `0` represents an arbitrary, potentially infinite number of values.
| Type/Property | Required? | Description |
|--------------------|-----------|------------------------------------------------------------------------------|
| @id | MUST | ID of the entry |
| @type | MUST | Is `owl:Restriction` |
| owl:onProperty | MUST | Describes the property tye his restriction belongs to |
| owl:minCardinality | MAY | Indicates whether a property is mandatory (1) or not (0). |
| owl:maxCardinality | MAY | Indicates whether a property may have multiple values (0) or only one (1). |
### RDFS Property
RDFS Properties, these represent predicates in triples.
They also specify, which classes they can interact with.
| Type/Property | Required? | Description |
|------------------------|-----------|---------------------------------------------------------------------------------------------------------|
| @id | MUST | ID of the entry |
| @type | MUST | Is `rdfs:Property` |
| owl:equivalentProperty | MAY | Ontological annotation https://www.w3.org/TR/owl-ref/#equivalentClass-def |
| schema:domainIncludes | MUST | Describes the possible types of the subject. This can be one or many. |
| schema:rangeIncludes | MUST | Describes the possible types of the object. This can be one or many. |
| rdfs:label | MAY | Label of the property |
| rdfs:comment | MAY | Human-readable description of the property |
## Metadata Representation
**Formal description:**
RO-Crate MUST include a graph description of the metadata entries.
This is expressed using 1 type:
- Metadata Entry
### RDF Metadata Entry
A metadata entry, described by a RDFS class.
| Type/Property | Required? | Description |
|---------------|-----------|----------------------------------------------------|
| @id | MUST | ID of the entry |
| @type | MUST | Type of the entry, MUST be at least one RDFS Class |
Further properties are included as specified in the RDFS description as fields.
# Reference Examples for both Schema and Entries
We created a small example. It can be found under:
`./examples/ro-crate-1.1/ro-crate-metadata/ro-crate-metadata.json.`
This describes the export
of `./examples/reference-openbis-export`.
# API
**Formal description:**
To be general, the API uses a lot of strings. This allows flexibility in the classes being used.
The interfaces are shown using Java since is a statically typed language, but they can be
implemented in most languages,
including Python and Javascript.
## Schema Representation DTOs
```Java
/* Represents a class, if we are talking about a schema, it is closely related with the definition of a table or type */
interface IType
{
/* Returns the ID of this type */
String getId();
/* Returns IDs of the types this type inherits from */
List<String> getSubClassOf();
/* Returns the ontological annotations of this type */
List<String> getOntologicalAnnotations();
/* Returns a human-readable description of this type */
String getComment();
/* Returns a human-readable label of this type */
String getLabel();
/* Get Restrictions placed on the properties of this type */
List<IRestriction> getResstrictions();
}
/* Represents a property in a graph, if we are talking about a schema, is closely related with a table column or type property */
interface IPropertyType
{
/* Returns the ID of this property type */
String getId();
/* Return possible values for the subject of this property type */
List<String> getDomain();
/* Return possible values for the object of this property type */
List<String> getRange();
/* Returns the ontological annotations of this property type */
List<String> getOntologicalAnnotations();
/* Returns whether this property has a min cardinality. 0 means optional, 1 means mandatory. */
int getMinCardinality();
/* Returns whether this property has a max cardinality. 0 means many values possible, 1 means only one is possible. */
int getMaxCardinality();
/* Returns a human-readable description of this type */
String getComment();
/* Returns a human-readable label of this type */
String getLabel();
}
```
## Metadata Representation DTOs
```Java
/* Represents a metadata entity. It is described */
interface IMetadataEntry
{
/**
* Returns the ID of this entry
*/
String getId();
/* Returns the type ID of this entry */
String getClassId();
/* These are key-value pairs for serialization. These are single-valued.
* Serializable classes are: String, Number and Boolean */
Map<String, Serializable> getValues();
/* These are references to other objects in the graph.
* Each key may have one or more references */
Map<String, List<String>> getReferences();
}
```
## Additional RO-Crate API Methods
```Java
/* The API to program against, this wraps around existing RO-Crate APIs. */
interface ISchemaFacade
{
/* Get the crate being worked on */
RoCrate getCrate();
/* Adds a single class */
void addType(IType rdfsClass);
/** Retrieves all Classes */
List<IType> getTypes();
/* Get a single type by its ID */
IType getTypes(String id);
/* Adds a single property */
void addPropertyType(IPropertyType property);
/* Get all Properties */
List<IPropertyType> getPropertyTypes();
/* Gets a single property by its ID. */
IPropertyType getPropertyType(String id);
/* Add a single metadata entry */
void addEntry(IMetadataEntry entry);
/* Get a single metadata entry by its ID */
IMetadataEntry getEntry(String id);
/* Get all metadata entities */
List<IMetadataEntry> getEntries(String rdfsClassId);
}
```
# Primitive Data Types
The following types from xsd are supported
| serialized as | in library | Usage |
|----------------|--------------|-------------------------------|
| xsd:integer | INTEGER | Any length of integer |
| xsd:float | FLOAT | 32-bit floating point number |
| xsd:double | DOUBLE | 64-bit floating point number |
| xsd:decimal | DECIMAL | Arbitrary size decimal number |
| xsd:float | FLOAT | 32-bit floating point number |
| xsd:datetime | DATETIME | Datetime |
| xsd:string | STRING | String |
| rdf:XMLLiteral | DATETIME | XML |
# API Reference Implementation in Java
A working implementation of the API for Java (source and compiled) can be found
under: `./lib/src`.
A compiled jar can be found under: `./lib/java/bin`.
The dependencies are specified in the module's `build.gradle`
file: `./lib/java/src/build.gradle`.
# API Reference Examples in Java
Working examples of the API in java to read and write can be found
at: `./`, specifically the class
files
- `./lib/java/src/java/ch/eth/sis/rocrate/example/ReadExample.java`
- `./lib/java/src/java/ch/eth/sis/rocrate/example/WriteExample.java`
# Ongoing Work / Future Plans
## More serialization formats
We are planning to investigate different formats for serializing schema, metadata and ontological annotations.
## Including reference ontologies inside the RO-Crate
One issue is that ontologies in RO-Crate are links. These can be subject to link rot.
To address this, reference ontologies are included in the RO-Crate. This helps interpretability and allows it to be shared more easily.
Think of it as docker for data!
## Separate files for schemas
At the moment, the graph inside the RO-Crate manifest can become large, unwieldy even.
Moving this into one or more separate files and referencing them in the manifest should keep things more manageable.
## Resolve schema.org types automagically
This allows using the schema.org without explicitly defining them in the schema.
It makes it easier to use the convention that is common in RO-Crate.
# People
- Andreas Meier (andreas.meier@ethz.ch)
- Juan Fuentes (juan.fuentes@id.ethz.ch)
+40
View File
@@ -0,0 +1,40 @@
# Ro-Crate SIS Specifications Directory
## Purpose
This repository contains Profiles/Modules specifications to use with RO-Crate.
It serves as a permanent URL for these specifications.
## Structure
Each specification is in a separate directory.
```
/specification-name/
```
This directory contains different versions, each identified by a directory names.
```
/specification-name/A.B.x/
```
Each version contains a specification file, `spec.md`.
The specification file indicates which RO-Crate versions it is compatible with.
PATCH versions are contained in the same directory, PATCHES are intended to fix issues that do not change the workings of the specification, e.g. typos.
Aside from this, the specifications are not changed after release.
```
/specification-name/A.B.x/spec.md
```
It may also contain library code in both source and compiled forms, if applicable.
```
/specification-name/A.B.x/spec.md/lib/
```