mirror of
https://github.com/researchobjectschema/ro-crate-interoperability-profile.git
synced 2026-05-17 16:16:48 +02:00
First commit, specification moved from https://sissource.ethz.ch/sispub/ro-crate/
This commit is contained in:
Binary file not shown.
BIN
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.
@@ -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
@@ -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.
BIN
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -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
@@ -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)
|
||||
@@ -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/
|
||||
```
|
||||
Reference in New Issue
Block a user