From d7340cad5c529951f47495ef4df6c210e48db8cd Mon Sep 17 00:00:00 2001 From: Philip Trembath Date: Wed, 4 Dec 2024 16:55:52 +0000 Subject: [PATCH 1/7] schema.org restructured --- templates/rocrate/rocrate.ftl | 4 +- templates/schema.org/_base.org.ftlh | 443 +++++++++++++++++++++++++++ templates/schema.org/schema.org.ftlh | 341 +-------------------- 3 files changed, 451 insertions(+), 337 deletions(-) create mode 100644 templates/schema.org/_base.org.ftlh diff --git a/templates/rocrate/rocrate.ftl b/templates/rocrate/rocrate.ftl index b420c9aa7..6be06f4a1 100644 --- a/templates/rocrate/rocrate.ftl +++ b/templates/rocrate/rocrate.ftl @@ -1,5 +1,5 @@ <#compress> - +<#include "../schema.org/_base.org.ftlh"> <#if type=='dataset' || type=='nonGeographicDataset' || type=='signpost'> <#assign docType = "Dataset"> <#elseif type=='aggregate' || type=='series'> @@ -20,7 +20,7 @@ "@id": "${uri?trim}" } }, - <#include "../schema.org/schema.org.ftlh"> + <@schemaDocument showFiles=true/> ] } diff --git a/templates/schema.org/_base.org.ftlh b/templates/schema.org/_base.org.ftlh new file mode 100644 index 000000000..dde812f97 --- /dev/null +++ b/templates/schema.org/_base.org.ftlh @@ -0,0 +1,443 @@ +<#import "../functions.ftlh" as func> + +<#if useConstraints?has_content> + <#assign licences = func.filter(useConstraints, "code", "license")> + +<#if responsibleParties?has_content> + <#assign authors = func.filter(responsibleParties, "role", "author") + pocs = func.filter(responsibleParties, "role", "pointOfContact") + publishers = func.filter(responsibleParties, "role", "publisher") > + +<#if onlineResources?has_content> + <#assign + infoLinks = func.filter(onlineResources, "function", "information") + > + + +<#-- COMPILE KEYWORD LIST---> + <#assign keywordList = [] > + + <#if descriptiveKeywords?has_content> + <#list descriptiveKeywords as descriptiveKeyword> + <#list descriptiveKeyword.keywords as keyword> + <#assign keywordList = keywordList + [keyword] > + + + + + <#if allKeywords?has_content> + <#list allKeywords as keyword> + <#assign keywordList = keywordList + [keyword]> + + + + <#--DE-DUPLICATE KEYWORD LIST --> + <#assign deDup = [] /> + <#list keywordList as originalList> + <#if ! deDup?seq_contains(originalList)> + <#assign deDup = deDup + [originalList] /> + + + <#assign keywordList = deDup?sort_by("value")?sort_by("uri") /> +<#-- END KEYWORD LIST---> + +<#if type=='dataset' || type=='nonGeographicDataset' || type=='signpost'> + <#assign docType = "Dataset"> +<#elseif type=='aggregate' || type=='series'> + <#assign docType = "Series"> +<#elseif type=='application'> + <#assign docType = "SoftwareSourceCode"> + + +<#macro schemaDocument showFiles=false> + { + "@type":<@displayLiteral docType/>, + "name":<@displayLiteral title/>, + + <#if showFiles> + <#if parts?? && parts?size gt 0> + <#if docType == "Dataset"> + "hasPart": [ + <#if isAttached!false> + <@partList fileDetails.getDetailsFor(id, true)/> + <#else> + <@partList fileDetails.getDetailsFor(id, false)/> + + ], + + + + + "@id": "${uri?trim}", + <#if datacitable?string == "true" && citation?has_content> + "identifier": { + "@type":"PropertyValue", + "propertyID": "https://registry.identifiers.org/registry/doi", + "value": "doi:${citation.doi}", + "url": "${citation.url}" + }, + "url": "${citation.url}", + "creditText":"${citation.authors?join(', ')} (${citation.year?string["0000"]}). ${citation.title}. ${citation.publisher}. (${codes.lookup('datacite.resourceTypeGeneral',citation.resourceTypeGeneral)}). ${citation.url}", + <#else> + "url":"${uri?trim}", + + + <#if resourceStatus != "Deleted"> + <#if description?has_content>"description":<@displayLiteral description/>, + + <#if alternateTitles?has_content> + "alternateName":[ + <#list alternateTitles as altTitle> + <@displayLiteral altTitle/><#sep>, + + ], + + + <#if resourceStatus == "Available"> + "isAccessibleForFree": true, + + + <#if datasetReferenceDate?? && datasetReferenceDate.creationDate?has_content> + "dateCreated":"${datasetReferenceDate.creationDate}", + + + <#if datasetReferenceDate?? && datasetReferenceDate.publicationDate?has_content> + "datePublished":"${datasetReferenceDate.publicationDate}", + + + <#if observedProperty?? && observedProperty?has_content> + "variableMeasured": [ <@observedPropertiesList observedProperty/>], + + + <#if keywordList?has_content> + "keywords": [<@keywordsList keywordList/>], + + + <#if authors?has_content> + "author": [<@contactList authors "author" />], + + + <#if pocs?has_content> + "contactPoint": [<@contactList pocs />], + + + <#--Citations--> + <#if incomingCitations?has_content> + "@reverse": { + "citation":[ + <@citationList incomingCitations /> + ] + }, + + + <#if temporalExtents?has_content> + "temporalCoverage":[ + <#list temporalExtents as temporal> + <#if temporal.begin?has_content> + <#assign begin = temporal.begin> + <#else> + <#assign begin = ""> + + <#if temporal.end?has_content> + <#assign end = temporal.end> + <#else> + <#assign end = ""> + + "${begin}/${end}"<#sep>, + + ], + + + <#if boundingBoxes?has_content> + "spatialCoverage": [ + <#list boundingBoxes as extent> + { + "@type":"Place", + "geo":{ + "@type":"GeoShape", + "box":"${extent.westBoundLongitude} ${extent.southBoundLatitude}, ${extent.eastBoundLongitude} ${extent.northBoundLatitude}" + } + }<#sep>, + + ], + + + <#if docType == "Dataset" || docType == "SoftwareSourceCode"> + + <#if licences?? && licences?has_content> + <#if licences?first.uri?? && licences?first.uri?has_content> + <#if licences?first.uri?matches("^http[s]?://eidc.ceh.ac.uk/licences/OGL.+$")> + "license": {"@id": "oglLicence"}, + <#else> + "license": "${licences?first.uri?trim}", + + + + + <#if downloads?has_content> + "distribution": [<@distributionList downloads />], + + + <#if publishers?has_content> + <#assign publisher = publishers?first> + <#if publisher.organisationIdentifier?has_content> + "publisher":{"@id":"${publisher.organisationIdentifier}"}, + + + + + "provider" : {"@id":"https://ror.org/04xw4m193"}, + "includedInDataCatalog":{"@type":"DataCatalog", "name":"Environmental Information Data Centre", "alternatename":"EIDC", "url":"https://catalogue.ceh.ac.uk/eidc/documents"}, + + <#else> + <#-- information to include if the dataset has been permanently deleted --> + "description": "This resource is no longer available please contact the Environmental Information Data Centre for more details", + "creativeWorkStatus": "Deleted", + + "@context":"http://schema.org/" + }, + { + "id": "https://ror.org/04xw4m193", + "@type":"Organization", + "name":"NERC EDS Environmental Information Data Centre", + "email": "info@eidc.ac.uk" + } + + <#if licences?? && licences?has_content> + <#if licences?first.uri?? && licences?first.uri?has_content> + <#if licences?first.uri?matches("^http[s]?://eidc.ceh.ac.uk/licences/OGL.+$")> + ,{ + "@id": "oglLicence", + "@type": "CreativeWork", + "name": "Open Government Licence v3", + "alternateName":"OGL-UK-3.0", + "license": "https://spdx.org/licenses/OGL-UK-3.0.html" + } + + + + + <#if authors?has_content> + ,<@contactDetails authors "author" /> + + + <#if pocs?has_content> + ,<@contactDetails pocs /> + + + <#if incomingCitations?has_content> + ,<@citationDetails incomingCitations /> + + + <#if showFiles> + <#if parts?? && parts?size gt 0> + <#if docType == "Dataset"> + <#if isAttached!false> + ,<@partDetails fileDetails.getDetailsFor(id, true)/> + <#else> + ,<@partDetails fileDetails.getDetailsFor(id, false)/> + + + + + + <#if downloads?has_content> + ,<@distributionDetails downloads /> + + + +<#macro keywordsList keywords> + <#list keywords as keyword> + <#if keyword.uri?has_content> + <#assign subjectScheme="" schemeURI=""> + <#if keyword.uri?matches("^http[s]?://inspire.ec.europa.eu/\\S+$")> + <#assign subjectScheme="European Union INSPIRE registry" schemeURI="http://inspire.ec.europa.eu/registry/"> + <#elseif keyword.uri?matches("^http[s]?://www.wikidata.org/entity/\\S+$")> + <#assign subjectScheme="Wikidata" schemeURI="https://www.wikidata.org/"> + <#elseif keyword.uri?matches("^http[s]?://sws.geonames.org/\\S+$")> + <#assign subjectScheme="Geonames" schemeURI="https://www.geonames.org/"> + <#elseif keyword.uri?matches("^http[s]?://www.eionet.europa.eu/gemet/concept/\\S+$")> + <#assign subjectScheme="GEMET concepts" schemeURI="https://www.eionet.europa.eu/gemet/"> + + <#t>{ + <#t>"@type": "DefinedTerm", + <#t>"@id": "${keyword.uri?trim}", + <#t>"name": <@displayLiteral keyword.value/> + <#t><#if subjectScheme?has_content>,"inDefinedTermSet": "${schemeURI}" + } + <#else> + "${keyword.value?trim}" + + <#sep>,<#t> + + + +<#macro observedPropertiesList props> + <#list props as op> + <#assign opLabel ="unknown"> + <#if op.title?has_content> + <#assign opLabel = op.title?trim> + <#elseif op.value?has_content> + <#assign opLabel = op.value?trim> + + + <#if op.uri?has_content> + { + "@type": "StatisticalVariable", + "@id": "${op.uri?trim}", + "name": "${opLabel}" + <#if op.unitsUri?has_content>,"unitCode": "${op.unitsUri?trim}" + <#if op.units?has_content>,"unitText": "${op.units?trim}" + } + <#else> + <@displayLiteral opLabel/> + + <#sep>, + + + +<#macro partList parts> + <#if parts?size lt 60000> + <#list parts as part> + <#if part.id?has_content>{"@id": "${part.id}"} <#sep>, + + <#else> + {"@id": "${id}-files"} + + + +<#macro partDeails parts> + <#if parts?size lt 60000> + <#list parts as part> + <#if part.id?has_content> + { + <#t>"@id": "${part.id}", + <#t>"name": "${part.id}" + <#if part.type?? && part.type?has_content><#t>,"@type": "${part.type}" + <#if part.encodingFormat?? && part.encodingFormat?has_content>,<#t>"encodingFormat": "${part.encodingFormat}" + <#if part.lastModified?? && part.lastModified?has_content>,<#t>"lastModified": "${part.lastModified}" + <#if part.bytes?? && part.bytes?has_content>,<#t>"bytes": ${part.bytes?long?c} + <#if part.contentUrl?? && part.contentUrl?has_content>,<#t>"contentUrl": "${part.contentUrl}" + } + + <#sep>,<#t> + + <#else> + { + "@id": "${id}-files", + "@type": "Dataset", + "name": "Files", + "description": "This dataset contains ${parts?size} files" + } + + + +<#macro contactList contacts prefix="contact"> + <#list contacts as contact> + <#assign contactid = "#" + prefix + contact?index> + <#if contact.individualName?has_content> + <#if contact.nameIdentifier?has_content && contact.nameIdentifier?matches("^http(|s)://orcid.org/\\d{4}-\\d{4}-\\d{4}-\\d{3}(X|\\d)$")> + <#assign contactid = contact.nameIdentifier> + + <#elseif contact.organisationName?has_content> + <#if contact.organisationIdentifier?has_content> + <#assign contactid = contact.organisationIdentifier > + + + {"@id": "${contactid}"}<#sep>, + + + +<#macro contactDetails contacts prefix="contact"> + <#list contacts as contact> + <#assign contactid = "#" + prefix + contact?index> + <#if contact.individualName?has_content> + <#if contact.nameIdentifier?has_content && contact.nameIdentifier?matches("^http(|s)://orcid.org/\\d{4}-\\d{4}-\\d{4}-\\d{3}(X|\\d)$")> + <#assign contactid = contact.nameIdentifier> + + <#elseif contact.organisationName?has_content> + <#if contact.organisationIdentifier?has_content> + <#assign contactid = contact.organisationIdentifier> + + + + { + "@id": "${contactid}", + <#if contact.individualName?has_content> + "@type": "Person", + "name": "${contact.individualName}" + <#if contact.email?has_content>,"email": "${contact.email}" + <#if contact.nameIdentifier?has_content && contact.nameIdentifier?matches("^http(|s)://orcid.org/\\d{4}-\\d{4}-\\d{4}-\\d{3}(X|\\d)$")> + ,"identifier": { + "@type":"PropertyValue", + "propertyID": "orcid", + "value": "${contact.nameIdentifier}" + } + + <#if contact.organisationName?has_content> + ,"affiliation":{ + "@type":"Organization", + "name":"${contact.organisationName}" + <#if contact.organisationIdentifier?has_content> + ,"identifier":"${contact.organisationIdentifier}" + + } + + <#else> + "@type":"Organization" + <#if contact.organisationName?has_content>,"name": "${contact.organisationName}" + <#if contact.email?has_content>,"email": "${contact.email}" + <#if contact.organisationIdentifier?has_content>,"identifier":"${contact.organisationIdentifier}" + + }<#sep>, + + + +<#macro citationList citations> + <#list incomingCitations as citation> + <#assign citationid = "#citation" + citation?index> + <#if citation.url?has_content><#assign citationid = citation.url> + {"@id": "${citationid}"}<#sep>, + + + +<#macro citationDetails citations> + <#list incomingCitations as citation> + <#assign citationid = "#citation" + citation?index> + <#if citation.url?has_content><#assign citationid = citation.url> + { + "@id": "${citationid}", + "@type": "CreativeWork" + <#if citation.description?has_content>,"creditText": <@displayLiteral citation.description/> + <#if citation.url?has_content>,"url": "${citation.url?trim}" + }<#sep>, + + + +<#macro distributionList distributions> + <#list downloads as distribution> + <#assign distributionid = "#distribution" + distribution?index> + {"@id": "${distributionid}"}<#sep>, + + + +<#macro distributionDetails distributions> + <#list downloads as distribution> + <#assign distributionid = "#distribution" + distribution?index> + { + "@id": "${distributionid}", + "@type":"DataDownload", + "contentUrl":"${distribution.url}" + <#if distribution.url?ends_with(".zip")>,"encodingFormat":"application/zip" + <#elseif distribution.url?ends_with(".csv")>,"encodingFormat":"text/csv" + <#elseif distribution.url?starts_with("https://data-package.ceh.ac.uk/data/")>,"encodingFormat":"application/zip" + <#elseif distribution.url?starts_with("https://catalogue.ceh.ac.uk/datastore")>,"encodingFormat":"text/directory" + + }<#sep>, + + + +<#macro displayLiteral string> + <#--Ensure literals do not contain " characters or line breaks--> + <#t>"${string?trim?replace("\"","'")?replace("\n"," ")}" + diff --git a/templates/schema.org/schema.org.ftlh b/templates/schema.org/schema.org.ftlh index b40948075..63b77ea65 100644 --- a/templates/schema.org/schema.org.ftlh +++ b/templates/schema.org/schema.org.ftlh @@ -1,45 +1,5 @@ -<#import "../functions.ftlh" as func> <#compress> - -<#if useConstraints?has_content> - <#assign licences = func.filter(useConstraints, "code", "license")> - -<#if responsibleParties?has_content> - <#assign authors = func.filter(responsibleParties, "role", "author") - publishers = func.filter(responsibleParties, "role", "publisher") > - -<#if onlineResources?has_content> - <#assign - infoLinks = func.filter(onlineResources, "function", "information") - > - - -<#-- COMPILE KEYWORD LIST---> - <#assign keywordList = [] > - - <#if descriptiveKeywords?has_content> - <#list descriptiveKeywords as descriptiveKeyword> - <#list descriptiveKeyword.keywords as keyword> - <#assign keywordList = keywordList + [keyword] > - - - - - <#if allKeywords?has_content> - <#list allKeywords as keyword> - <#assign keywordList = keywordList + [keyword]> - - - - <#--DE-DUPLICATE KEYWORD LIST --> - <#assign deDup = [] /> - <#list keywordList as originalList> - <#if ! deDup?seq_contains(originalList)> - <#assign deDup = deDup + [originalList] /> - - - <#assign keywordList = deDup?sort_by("value")?sort_by("uri") /> -<#-- END KEYWORD LIST---> +<#include "../schema.org/_base.org.ftlh"> <#if type=='dataset' || type=='nonGeographicDataset' || type=='signpost'> <#assign docType = "Dataset"> @@ -50,299 +10,10 @@ <#if docType?has_content> - { - "@type":<@displayLiteral docType/>, - "name":<@displayLiteral title/>, - - <#if docType == "Dataset"> - <#if isAttached!false> - <@displayParts fileDetails.getDetailsFor(id, true)/> - <#else> - <@displayParts fileDetails.getDetailsFor(id, false)/> - - - - <#if datacitable?string == "true" && citation?has_content> - "@id": "${citation.url}", - "identifier": { - "@type":"PropertyValue", - "propertyID": "doi", - "value": "${citation.url}" - }, - "url": "${citation.url}", - "creditText":"${citation.authors?join(', ')} (${citation.year?string["0000"]}). ${citation.title}. ${citation.publisher}. (${codes.lookup('datacite.resourceTypeGeneral',citation.resourceTypeGeneral)}). ${citation.url}", - <#else> - "@id": "${uri?trim}", - "url":"${uri?trim}", - - - <#if resourceStatus != "Deleted"> - <#if description?has_content>"description":<@displayLiteral description/>, - - <#if alternateTitles?has_content> - "alternateName":[ - <#list alternateTitles as altTitle> - <@displayLiteral altTitle/><#sep>, - - ], - - - <#if resourceStatus == "Available"> - "isAccessibleForFree": true, - - - <#if datasetReferenceDate?? && datasetReferenceDate.creationDate?has_content> - "dateCreated":"${datasetReferenceDate.creationDate}", - - - <#if datasetReferenceDate?? && datasetReferenceDate.publicationDate?has_content> - "datePublished":"${datasetReferenceDate.publicationDate}", - - - <#if observedProperty?? && observedProperty?has_content> - "variableMeasured": [ <@displayObservedProperties observedProperty/>], - - - <#if keywordList?has_content> - "keywords": [<@displayKeywords keywordList/>], - - - <#--Authors--> - <#if authors?has_content> - "creator":[ - <#list authors as author> - <#if author.individualName?has_content> - { - "@type":"Person", - "name": "${author.individualName}" - <#if author.organisationName?has_content> - ,"email": "${author.email}" - - <#if author.nameIdentifier?has_content && author.nameIdentifier?matches("^http(|s)://orcid.org/\\d{4}-\\d{4}-\\d{4}-\\d{3}(X|\\d)$")> - ,"identifier": { - "@type":"PropertyValue", - "propertyID": "orcid", - "value": "${author.nameIdentifier}" - } - - <#if author.organisationName?has_content> - ,"affiliation":{ - "@type":"Organization", - "name":"${author.organisationName}" - <#if author.organisationIdentifier?has_content> - ,"identifier":"${author.organisationIdentifier}" - - } - - } - <#else> - { - "@type":"Organization", - "name": "${author.organisationName}" - <#if author.organisationName?has_content> - ,"email": "${author.email}" - - <#if author.organisationIdentifier?has_content> - ,"identifier":"${author.organisationIdentifier}" - - } - - <#sep>, - - ] - , - - - <#--Citations--> - <#if incomingCitations?has_content> - "@reverse": { - "citation":[ - <#list incomingCitations as citation> - { - "@type": "CreativeWork" - <#if citation.description?has_content>,"creditText": <@displayLiteral citation.description/> - <#if citation.url?has_content>,"url": "${citation.url?trim}" - }<#sep>, - - ] - }, - - - <#if temporalExtents?has_content> - "temporalCoverage":[ - <#list temporalExtents as temporal> - <#if temporal.begin?has_content> - <#assign begin = temporal.begin> - <#else> - <#assign begin = ""> - - <#if temporal.end?has_content> - <#assign end = temporal.end> - <#else> - <#assign end = ""> - - "${begin}/${end}"<#sep>, - - ], - - - <#if boundingBoxes?has_content> - "spatialCoverage": [ - <#list boundingBoxes as extent> - { - "@type":"Place", - "geo":{ - "@type":"GeoShape", - "box":"${extent.westBoundLongitude} ${extent.southBoundLatitude}, ${extent.eastBoundLongitude} ${extent.northBoundLatitude}" - } - }<#sep>, - - ], - - - <#if docType == "Dataset" || docType == "SoftwareSourceCode"> - - <#if licences?? && licences?has_content> - <#if licences?first.uri?? && licences?first.uri?has_content> - <#if licences?first.uri?matches("^http[s]?://eidc.ceh.ac.uk/licences/OGL.+$")> - "license": { - "@type": "CreativeWork", - "name": "Open Government Licence v3", - "alternateName":"OGL-UK-3.0", - "license": "https://spdx.org/licenses/OGL-UK-3.0.html" - }, - <#else> - "license": "${licences?first.uri?trim}", - - - - - <#--Distributions--> - <#list downloads> - "distribution":[ - <#items as download> - { - "@type":"DataDownload", - "contentUrl":"${download.url}" - <#if download.url?ends_with(".zip")>,"encodingFormat":"application/zip" - <#elseif download.url?ends_with(".csv")>,"encodingFormat":"text/csv" - <#elseif download.url?starts_with("https://data-package.ceh.ac.uk/data/")>,"encodingFormat":"application/zip" - <#elseif download.url?starts_with("https://catalogue.ceh.ac.uk/datastore")>,"encodingFormat":"text/directory" - }<#sep>, - - ], - - - <#if publishers?has_content> - <#assign publisher = publishers?first> - "publisher": - { - "@type":"Organization","name":"${publisher.organisationName}" - <#if publisher.organisationIdentifier?has_content> - ,"identifier":"${publisher.organisationIdentifier}" - - <#if publisher.organisationName?has_content> - ,"email": "${publisher.email}" - - }, - - - - "provider" : {"@type":"Organization","name":"Environmental Information Data Centre"}, - "includedInDataCatalog":{"@type":"DataCatalog", "name":"Environmental Information Data Centre", "alternatename":"EIDC", "url":"https://catalogue.ceh.ac.uk/eidc/documents"}, - - <#else> - <#-- information to include if the dataset has been permanently deleted --> - "description": "This resource is no longer available please contact the Environmental Information Data Centre for more details", - "creativeWorkStatus": "Deleted", - - - "@context":"http://schema.org/" - } + { + "@graph": [ + <@schemaDocument /> + ] + } - -<#macro displayKeywords keywords> - <#list keywords as keyword> - <#if keyword.uri?has_content> - <#assign subjectScheme="" schemeURI=""> - <#if keyword.uri?matches("^http[s]?://inspire.ec.europa.eu/\\S+$")> - <#assign subjectScheme="European Union INSPIRE registry" schemeURI="http://inspire.ec.europa.eu/registry/"> - <#elseif keyword.uri?matches("^http[s]?://www.wikidata.org/entity/\\S+$")> - <#assign subjectScheme="Wikidata" schemeURI="https://www.wikidata.org/"> - <#elseif keyword.uri?matches("^http[s]?://sws.geonames.org/\\S+$")> - <#assign subjectScheme="Geonames" schemeURI="https://www.geonames.org/"> - <#elseif keyword.uri?matches("^http[s]?://www.eionet.europa.eu/gemet/concept/\\S+$")> - <#assign subjectScheme="GEMET concepts" schemeURI="https://www.eionet.europa.eu/gemet/"> - - <#t>{ - <#t>"@type": "DefinedTerm", - <#t>"@id": "${keyword.uri?trim}", - <#t>"name": <@displayLiteral keyword.value/> - <#t><#if subjectScheme?has_content>,"inDefinedTermSet": "${schemeURI}" - } - <#else> - "${keyword.value?trim}" - - <#sep>,<#t> - - - -<#macro displayObservedProperties props> - <#list props as op> - <#assign opLabel ="unknown"> - <#if op.title?has_content> - <#assign opLabel = op.title?trim> - <#elseif op.value?has_content> - <#assign opLabel = op.value?trim> - - - <#if op.uri?has_content> - { - "@type": "StatisticalVariable", - "@id": "${op.uri?trim}", - "name": "${opLabel}" - <#if op.unitsUri?has_content>,"unitCode": "${op.unitsUri?trim}" - <#if op.units?has_content>,"unitText": "${op.units?trim}" - } - <#else> - <@displayLiteral opLabel/> - - <#sep>, - - - -<#macro displayParts parts> - <#if parts?size gt 0> - "hasPart": [ - <#if parts?size lt 60000> - <#list parts as part> - <#if part.id?has_content> - { - <#t>"@id": "${part.id}", - <#t>"@type": "${part.type}", - <#t>"name": "${part.id}", - <#if part.encodingFormat?? && part.encodingFormat?has_content><#t>"encodingFormat": "${part.encodingFormat}", - <#t>"lastModified": "${part.lastModified}", - <#t>"bytes": ${part.bytes?long?c}, - <#t>"contentUrl": "${part.contentUrl}" - } - - <#sep>,<#t> - - <#else> - { - "@id": "${id}-files", - "@type": "Dataset", - "name": "Files", - "description": "This dataset contains ${parts?size} files" - } - - ], - - - -<#macro displayLiteral string> - <#--Ensure literals do not contain " characters or line breaks--> - <#t>"${string?trim?replace("\"","'")?replace("\n"," ")}" - From dcdf1a110a75b71f907399d5ce1b248e92e6bc97 Mon Sep 17 00:00:00 2001 From: Philip Trembath Date: Wed, 4 Dec 2024 17:35:26 +0000 Subject: [PATCH 2/7] found a booktrap bug --- templates/html/search/_page.ftlh | 2 +- web/scss/search.scss | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/templates/html/search/_page.ftlh b/templates/html/search/_page.ftlh index d70ea44ad..796e85f24 100644 --- a/templates/html/search/_page.ftlh +++ b/templates/html/search/_page.ftlh @@ -23,7 +23,7 @@ + <#if (result.resourceStatus??)>result--${result.resourceStatus}" data-location="${(result.locations?join('|'))!}" id="${result.identifier}">
${(codes.lookup("publication.state", result.state)!)!?upper_case!''}
diff --git a/web/scss/search.scss b/web/scss/search.scss index dae98fd6b..588d2becb 100644 --- a/web/scss/search.scss +++ b/web/scss/search.scss @@ -164,7 +164,7 @@ main { .leaflet-control-layers-list { overflow: hidden; - padding:0.5em; + padding: 0.5em; font-size: 1em; } @@ -225,6 +225,16 @@ main { font-size: 0.9rem; padding-block-start: 3px; } + + .opstatus { + display: none; + } + } + + &.opstatus-Inactive { + .opstatus { + display: inline-block; + } } &__title { From 2ea9b317e5defbb740fe8d32e377fe605deef23d Mon Sep 17 00:00:00 2001 From: Philip Trembath Date: Thu, 5 Dec 2024 12:57:00 +0000 Subject: [PATCH 3/7] update schema.org base --- templates/schema.org/_base.org.ftlh | 81 +++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 21 deletions(-) diff --git a/templates/schema.org/_base.org.ftlh b/templates/schema.org/_base.org.ftlh index dde812f97..acdb8c302 100644 --- a/templates/schema.org/_base.org.ftlh +++ b/templates/schema.org/_base.org.ftlh @@ -148,18 +148,17 @@ ], + <#if boundingBoxes?has_content> "spatialCoverage": [ - <#list boundingBoxes as extent> - { - "@type":"Place", - "geo":{ - "@type":"GeoShape", - "box":"${extent.westBoundLongitude} ${extent.southBoundLatitude}, ${extent.eastBoundLongitude} ${extent.northBoundLatitude}" - } - }<#sep>, - - ], + <@itemList boundingBoxes "bbox"/> + ], + + + <#if funding?has_content> + "funder": [ + <@itemList funding "fund"/> + ], <#if docType == "Dataset" || docType == "SoftwareSourceCode"> @@ -175,7 +174,7 @@ <#if downloads?has_content> - "distribution": [<@distributionList downloads />], + "distribution": [<@itemList downloads "distribution" />], <#if publishers?has_content> @@ -187,7 +186,7 @@ "provider" : {"@id":"https://ror.org/04xw4m193"}, - "includedInDataCatalog":{"@type":"DataCatalog", "name":"Environmental Information Data Centre", "alternatename":"EIDC", "url":"https://catalogue.ceh.ac.uk/eidc/documents"}, + "includedInDataCatalog":{ "@id": "#eidc-dataCatalogue"}, <#else> <#-- information to include if the dataset has been permanently deleted --> @@ -197,7 +196,14 @@ "@context":"http://schema.org/" }, { - "id": "https://ror.org/04xw4m193", + "@id": "#eidc-dataCatalogue", + "@type":"DataCatalog", + "name":"Environmental Information Data Centre", + "alternatename":"EIDC", + "url":"https://catalogue.ceh.ac.uk/eidc/documents" + }, + { + "@id": "https://ror.org/04xw4m193", "@type":"Organization", "name":"NERC EDS Environmental Information Data Centre", "email": "info@eidc.ac.uk" @@ -217,6 +223,10 @@ + <#if boundingBoxes?has_content> + ,<@bboxDetails boundingBoxes /> + + <#if authors?has_content> ,<@contactDetails authors "author" /> @@ -229,6 +239,10 @@ ,<@citationDetails incomingCitations /> + <#if funding?has_content> + ,<@fundDetails funding /> + + <#if showFiles> <#if parts?? && parts?size gt 0> <#if docType == "Dataset"> @@ -332,9 +346,16 @@ -<#macro contactList contacts prefix="contact"> +<#macro itemList list idlabel="item"> + <#list list as item> + <#assign itemid = "#" + idlabel + item?index> + {"@id": "${itemid}"}<#sep>, + + + +<#macro contactList contacts idlabel="contact"> <#list contacts as contact> - <#assign contactid = "#" + prefix + contact?index> + <#assign contactid = "#" + idlabel + contact?index> <#if contact.individualName?has_content> <#if contact.nameIdentifier?has_content && contact.nameIdentifier?matches("^http(|s)://orcid.org/\\d{4}-\\d{4}-\\d{4}-\\d{3}(X|\\d)$")> <#assign contactid = contact.nameIdentifier> @@ -348,9 +369,9 @@ -<#macro contactDetails contacts prefix="contact"> +<#macro contactDetails contacts idlabel="contact"> <#list contacts as contact> - <#assign contactid = "#" + prefix + contact?index> + <#assign contactid = "#" + idlabel + contact?index> <#if contact.individualName?has_content> <#if contact.nameIdentifier?has_content && contact.nameIdentifier?matches("^http(|s)://orcid.org/\\d{4}-\\d{4}-\\d{4}-\\d{3}(X|\\d)$")> <#assign contactid = contact.nameIdentifier> @@ -414,10 +435,17 @@ -<#macro distributionList distributions> - <#list downloads as distribution> - <#assign distributionid = "#distribution" + distribution?index> - {"@id": "${distributionid}"}<#sep>, +<#macro bboxDetails boundingBoxes> + <#list boundingBoxes as bbox> + <#assign bboxid = "#bbox" + bbox?index> + { + "@id": "${bboxid}", + "@type":"Place", + "geo":{ + "@type":"GeoShape", + "box":"${bbox.westBoundLongitude} ${bbox.southBoundLatitude}, ${bbox.eastBoundLongitude} ${bbox.northBoundLatitude}" + } + }<#sep>, @@ -437,6 +465,17 @@ +<#macro fundDetails funding> + <#list funding as fund> + <#assign fundid = "#fund" + fund?index> + { + "@id": "${fundid}", + "@type":"Organization" + <#if fund.funderName?? && fund.funderName?has_content>,<#t>"name":"${fund.funderName}" + }<#sep>, + + + <#macro displayLiteral string> <#--Ensure literals do not contain " characters or line breaks--> <#t>"${string?trim?replace("\"","'")?replace("\n"," ")}" From 951f5703b792ef58309f391537e338ed77f06594 Mon Sep 17 00:00:00 2001 From: Rod Scott Date: Wed, 11 Dec 2024 16:31:33 +0000 Subject: [PATCH 4/7] Adding test for RO-Crate templates EMC-381 --- .../java/templates/DataciteTemplateTest.java | 6 +- java/src/test/java/templates/RoCrateTest.java | 92 +++++++++++++++++++ .../{ => datacite}/contributors-full.xml | 0 .../templates/{ => datacite}/related-full.xml | 0 .../{ => datacite}/subjects-full.xml | 0 .../templates/rocrate/attached-minimal.json | 35 +++++++ .../resources/templates/rocrate/minimal.json | 35 +++++++ 7 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 java/src/test/java/templates/RoCrateTest.java rename java/src/test/resources/templates/{ => datacite}/contributors-full.xml (100%) rename java/src/test/resources/templates/{ => datacite}/related-full.xml (100%) rename java/src/test/resources/templates/{ => datacite}/subjects-full.xml (100%) create mode 100644 java/src/test/resources/templates/rocrate/attached-minimal.json create mode 100644 java/src/test/resources/templates/rocrate/minimal.json diff --git a/java/src/test/java/templates/DataciteTemplateTest.java b/java/src/test/java/templates/DataciteTemplateTest.java index ed6ebfcef..45b92cd05 100644 --- a/java/src/test/java/templates/DataciteTemplateTest.java +++ b/java/src/test/java/templates/DataciteTemplateTest.java @@ -87,7 +87,7 @@ void related() { gemini.setUri(uri); val jena = mock(JenaLookupService.class); configuration.setSharedVariable("jena", jena); - val expected = expected("related-full.xml"); + val expected = expected("datacite/related-full.xml"); given(jena.relationships(uri, "https://vocabs.ceh.ac.uk/eidc#supersedes")).willReturn(List.of( Link.builder().href("https://catalogue.ceh.ac.uk/id/847463839").build() @@ -140,7 +140,7 @@ void full() { .build() )); - val expected = expected("subjects-full.xml"); + val expected = expected("datacite/subjects-full.xml"); //when val actual = template("_subjects.ftlx"); @@ -195,7 +195,7 @@ void full() { custodian )); - val expected = expected("contributors-full.xml"); + val expected = expected("datacite/contributors-full.xml"); //when val actual = template("_contributors.ftlx"); diff --git a/java/src/test/java/templates/RoCrateTest.java b/java/src/test/java/templates/RoCrateTest.java new file mode 100644 index 000000000..e467cf944 --- /dev/null +++ b/java/src/test/java/templates/RoCrateTest.java @@ -0,0 +1,92 @@ +package templates; + +import freemarker.template.Configuration; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.skyscreamer.jsonassert.JSONAssert; +import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; +import uk.ac.ceh.gateway.catalogue.gemini.GeminiDocument; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +@Slf4j +@DisplayName("RO-Crate") +public class RoCrateTest { + + Configuration configuration; + GeminiDocument gemini; + + @SneakyThrows + private String expected(String filename) { + val expected = Objects.requireNonNull(getClass().getResourceAsStream(filename)); + return IOUtils.toString(expected, StandardCharsets.UTF_8); + } + + @SneakyThrows + private String template(String templateFilename) { + return FreeMarkerTemplateUtils.processTemplateIntoString( + configuration.getTemplate(templateFilename), + gemini + ); + } + + @SneakyThrows + @BeforeEach + void init() { + configuration = new Configuration(Configuration.VERSION_2_3_23); + configuration.setDirectoryForTemplateLoading(new File("../templates")); + gemini = new GeminiDocument(); + } + + @Nested + @DisplayName("Attached") + class Attached { + + @SneakyThrows + @Test + void rocrateAttachedMinimal() { + //given + val uri = "https://example.org/id/123456789"; + gemini.setUri(uri); + gemini.setTitle("Title"); + gemini.setType("dataset"); + val expected = expected("rocrate/attached-minimal.json"); + + //when + val actual = template("rocrate/rocrate_attached.ftl"); + + //then + JSONAssert.assertEquals(expected, actual, true); + } + } + + @Nested + @DisplayName("Detached") + class Detached { + + @SneakyThrows + @Test + void rocrateMinimal() { + //given + val uri = "https://example.org/id/123456789"; + gemini.setUri(uri); + gemini.setTitle("Title"); + gemini.setType("dataset"); + val expected = expected("rocrate/minimal.json"); + + //when + val actual = template("rocrate/rocrate.ftl"); + + //then + JSONAssert.assertEquals(expected, actual, true); + } + } +} diff --git a/java/src/test/resources/templates/contributors-full.xml b/java/src/test/resources/templates/datacite/contributors-full.xml similarity index 100% rename from java/src/test/resources/templates/contributors-full.xml rename to java/src/test/resources/templates/datacite/contributors-full.xml diff --git a/java/src/test/resources/templates/related-full.xml b/java/src/test/resources/templates/datacite/related-full.xml similarity index 100% rename from java/src/test/resources/templates/related-full.xml rename to java/src/test/resources/templates/datacite/related-full.xml diff --git a/java/src/test/resources/templates/subjects-full.xml b/java/src/test/resources/templates/datacite/subjects-full.xml similarity index 100% rename from java/src/test/resources/templates/subjects-full.xml rename to java/src/test/resources/templates/datacite/subjects-full.xml diff --git a/java/src/test/resources/templates/rocrate/attached-minimal.json b/java/src/test/resources/templates/rocrate/attached-minimal.json new file mode 100644 index 000000000..770e06135 --- /dev/null +++ b/java/src/test/resources/templates/rocrate/attached-minimal.json @@ -0,0 +1,35 @@ +{ + "@context": "https://w3id.org/ro/crate/1.1/context", + "@graph": [ + { + "@type": "CreativeWork", + "@id": "ro-crate-metadata.json", + "conformsTo": { "@id": "https://w3id.org/ro/crate/1.1" }, + "about": { + "@id": "https://example.org/id/123456789" + } + }, + { + "@type":"Dataset", + "name":"Title", + "@id": "https://example.org/id/123456789", + "url":"https://example.org/id/123456789", + "provider" : {"@id":"https://ror.org/04xw4m193"}, + "includedInDataCatalog":{ "@id": "#eidc-dataCatalogue"}, + "@context":"http://schema.org/" + }, + { + "@id": "#eidc-dataCatalogue", + "@type":"DataCatalog", + "name":"Environmental Information Data Centre", + "alternatename":"EIDC", + "url":"https://catalogue.ceh.ac.uk/eidc/documents" + }, + { + "@id": "https://ror.org/04xw4m193", + "@type":"Organization", + "name":"NERC EDS Environmental Information Data Centre", + "email": "info@eidc.ac.uk" + } + ] +} diff --git a/java/src/test/resources/templates/rocrate/minimal.json b/java/src/test/resources/templates/rocrate/minimal.json new file mode 100644 index 000000000..770e06135 --- /dev/null +++ b/java/src/test/resources/templates/rocrate/minimal.json @@ -0,0 +1,35 @@ +{ + "@context": "https://w3id.org/ro/crate/1.1/context", + "@graph": [ + { + "@type": "CreativeWork", + "@id": "ro-crate-metadata.json", + "conformsTo": { "@id": "https://w3id.org/ro/crate/1.1" }, + "about": { + "@id": "https://example.org/id/123456789" + } + }, + { + "@type":"Dataset", + "name":"Title", + "@id": "https://example.org/id/123456789", + "url":"https://example.org/id/123456789", + "provider" : {"@id":"https://ror.org/04xw4m193"}, + "includedInDataCatalog":{ "@id": "#eidc-dataCatalogue"}, + "@context":"http://schema.org/" + }, + { + "@id": "#eidc-dataCatalogue", + "@type":"DataCatalog", + "name":"Environmental Information Data Centre", + "alternatename":"EIDC", + "url":"https://catalogue.ceh.ac.uk/eidc/documents" + }, + { + "@id": "https://ror.org/04xw4m193", + "@type":"Organization", + "name":"NERC EDS Environmental Information Data Centre", + "email": "info@eidc.ac.uk" + } + ] +} From b0468970dce5a9659f6138020951031be6e66cad Mon Sep 17 00:00:00 2001 From: Philip Trembath Date: Thu, 12 Dec 2024 12:39:57 +0000 Subject: [PATCH 5/7] schema.org _base updated to remove redundancies --- templates/schema.org/_base.org.ftlh | 33 +++++------------------------ 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/templates/schema.org/_base.org.ftlh b/templates/schema.org/_base.org.ftlh index acdb8c302..dfd1c9eef 100644 --- a/templates/schema.org/_base.org.ftlh +++ b/templates/schema.org/_base.org.ftlh @@ -3,43 +3,20 @@ <#if useConstraints?has_content> <#assign licences = func.filter(useConstraints, "code", "license")> -<#if responsibleParties?has_content> - <#assign authors = func.filter(responsibleParties, "role", "author") - pocs = func.filter(responsibleParties, "role", "pointOfContact") - publishers = func.filter(responsibleParties, "role", "publisher") > - <#if onlineResources?has_content> <#assign infoLinks = func.filter(onlineResources, "function", "information") > -<#-- COMPILE KEYWORD LIST---> - <#assign keywordList = [] > - - <#if descriptiveKeywords?has_content> - <#list descriptiveKeywords as descriptiveKeyword> - <#list descriptiveKeyword.keywords as keyword> - <#assign keywordList = keywordList + [keyword] > - - - - - <#if allKeywords?has_content> - <#list allKeywords as keyword> - <#assign keywordList = keywordList + [keyword]> - - - <#--DE-DUPLICATE KEYWORD LIST --> <#assign deDup = [] /> - <#list keywordList as originalList> - <#if ! deDup?seq_contains(originalList)> - <#assign deDup = deDup + [originalList] /> + <#list allKeywords as keywords> + <#if ! deDup?seq_contains(keywords)> + <#assign deDup = deDup + [keywords] /> <#assign keywordList = deDup?sort_by("value")?sort_by("uri") /> -<#-- END KEYWORD LIST---> <#if type=='dataset' || type=='nonGeographicDataset' || type=='signpost'> <#assign docType = "Dataset"> @@ -117,8 +94,8 @@ "author": [<@contactList authors "author" />], - <#if pocs?has_content> - "contactPoint": [<@contactList pocs />], + <#if pointsOfContact ?has_content> + "contactPoint": [<@contactList pointsOfContact />], <#--Citations--> From 24c7600d382a5306fa99133c8970f954e563c831 Mon Sep 17 00:00:00 2001 From: Rod Scott Date: Fri, 13 Dec 2024 16:46:50 +0000 Subject: [PATCH 6/7] Part way through RO-Crate template refactoring EMC-381 --- .../catalogue/gemini/GeminiDocument.java | 15 ++ .../templateHelpers/FileDetailsService.java | 2 +- java/src/test/java/templates/RoCrateTest.java | 121 ++++++++- .../templates/rocrate/attached-minimal.json | 2 +- .../resources/templates/rocrate/full.json | 124 +++++++++ .../resources/templates/rocrate/minimal.json | 8 +- templates/schema.org/_base.org.ftlh | 238 ++++++++---------- 7 files changed, 364 insertions(+), 146 deletions(-) create mode 100644 java/src/test/resources/templates/rocrate/full.json diff --git a/java/src/main/java/uk/ac/ceh/gateway/catalogue/gemini/GeminiDocument.java b/java/src/main/java/uk/ac/ceh/gateway/catalogue/gemini/GeminiDocument.java index e90cc063f..eab50cd15 100644 --- a/java/src/main/java/uk/ac/ceh/gateway/catalogue/gemini/GeminiDocument.java +++ b/java/src/main/java/uk/ac/ceh/gateway/catalogue/gemini/GeminiDocument.java @@ -323,6 +323,21 @@ public long getIncomingCitationCount() { .orElse(0); } + public List getLicences() { + return Optional.ofNullable(useConstraints) + .orElseGet(Collections::emptyList) + .stream().filter(resourceConstraint -> resourceConstraint.getCode().equalsIgnoreCase("license")) + .collect(Collectors.toCollection(ArrayList::new)); + } + + public List getInfoLinks() { + return Optional.ofNullable(onlineResources) + .orElseGet(Collections::emptyList) + .stream() + .filter(onlineResource -> onlineResource.getFunction().equalsIgnoreCase("information")) + .collect(Collectors.toCollection(ArrayList::new)); + } + private static @NonNull String convertEmail(@NonNull String email) { return email.endsWith("@ceh.ac.uk") ? "enquiries@ceh.ac.uk" : email; } diff --git a/java/src/main/java/uk/ac/ceh/gateway/catalogue/templateHelpers/FileDetailsService.java b/java/src/main/java/uk/ac/ceh/gateway/catalogue/templateHelpers/FileDetailsService.java index ccdaad8ce..90f946b6b 100644 --- a/java/src/main/java/uk/ac/ceh/gateway/catalogue/templateHelpers/FileDetailsService.java +++ b/java/src/main/java/uk/ac/ceh/gateway/catalogue/templateHelpers/FileDetailsService.java @@ -92,7 +92,7 @@ private String path(boolean isAttached, String fileId, String path){ } @lombok.Value - public class Part { + public static class Part { String id, type, name, encodingFormat, contentUrl; Long bytes; LocalDateTime lastModified; diff --git a/java/src/test/java/templates/RoCrateTest.java b/java/src/test/java/templates/RoCrateTest.java index e467cf944..6bf7b83d0 100644 --- a/java/src/test/java/templates/RoCrateTest.java +++ b/java/src/test/java/templates/RoCrateTest.java @@ -9,20 +9,64 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; import org.skyscreamer.jsonassert.JSONAssert; import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; +import uk.ac.ceh.gateway.catalogue.citation.Citation; +import uk.ac.ceh.gateway.catalogue.gemini.AccessLimitation; +import uk.ac.ceh.gateway.catalogue.gemini.DatasetReferenceDate; import uk.ac.ceh.gateway.catalogue.gemini.GeminiDocument; +import uk.ac.ceh.gateway.catalogue.gemini.Keyword; +import uk.ac.ceh.gateway.catalogue.model.ObservedProperty; +import uk.ac.ceh.gateway.catalogue.model.ResponsibleParty; +import uk.ac.ceh.gateway.catalogue.templateHelpers.CodeLookupService; +import uk.ac.ceh.gateway.catalogue.templateHelpers.FileDetailsService; import java.io.File; import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; import java.util.Objects; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; + @Slf4j @DisplayName("RO-Crate") +@ExtendWith(MockitoExtension.class) public class RoCrateTest { Configuration configuration; GeminiDocument gemini; + @Mock + CodeLookupService codeLookupService; + @Mock + FileDetailsService fileDetailsService; + + private void givenCodeLookupService() { + given(codeLookupService.lookup("datacite.resourceTypeGeneral", "resourceType")) + .willReturn("Resource Type"); + } + + private void givenFileDetailsService(String fileId) { + given(fileDetailsService.getDetailsFor(fileId, false)) + .willReturn(List.of( + new FileDetailsService.Part(fileId, "File", "name1", "text/csv", "https://example.com/name1", 12L, LocalDateTime.of(2024,12,9,15, 34)), + new FileDetailsService.Part(fileId, "File", "name2", "text/csv", "https://example.com/name2", 9832L, LocalDateTime.of(2020,5,6,23, 59)) + )); + } + + private GeminiDocument createGeminiDocument(String fileId) { + val gemini = new GeminiDocument(); + gemini.setUri("https://example.org/id/" + fileId); + gemini.setId(fileId); + gemini.setTitle("Title"); + gemini.setType("dataset"); + return gemini; + } @SneakyThrows private String expected(String filename) { @@ -43,7 +87,8 @@ private String template(String templateFilename) { void init() { configuration = new Configuration(Configuration.VERSION_2_3_23); configuration.setDirectoryForTemplateLoading(new File("../templates")); - gemini = new GeminiDocument(); + configuration.setSharedVariable("codes", codeLookupService); + configuration.setSharedVariable("fileDetails", fileDetailsService); } @Nested @@ -54,10 +99,7 @@ class Attached { @Test void rocrateAttachedMinimal() { //given - val uri = "https://example.org/id/123456789"; - gemini.setUri(uri); - gemini.setTitle("Title"); - gemini.setType("dataset"); + gemini = createGeminiDocument("123456789"); val expected = expected("rocrate/attached-minimal.json"); //when @@ -76,10 +118,7 @@ class Detached { @Test void rocrateMinimal() { //given - val uri = "https://example.org/id/123456789"; - gemini.setUri(uri); - gemini.setTitle("Title"); - gemini.setType("dataset"); + gemini = createGeminiDocument("09837382"); val expected = expected("rocrate/minimal.json"); //when @@ -88,5 +127,69 @@ void rocrateMinimal() { //then JSONAssert.assertEquals(expected, actual, true); } + + @SneakyThrows + @Test + void rocrateFull() { + //given + val expected = expected("rocrate/full.json"); + + val fileId = "882739943"; + gemini = createGeminiDocument(fileId); + + // partsList & partDetails + givenFileDetailsService(fileId); + + // datacite + givenCodeLookupService(); + gemini.setDatacitable(true); + gemini.setCitation(Citation.builder() + .doi("10.5285/" + fileId) + .authors(List.of("Able", "Bracken", "Charles")) + .year(2020) + .title("Title") + .publisher("Publisher") + .resourceTypeGeneral("resourceType") + .build()); + + // resourceStatus not Deleted + gemini.setAccessLimitation(AccessLimitation.builder() + .code("Available") + .build()); + gemini.setDescription("Description"); + gemini.setAlternateTitles(List.of("Alternate Title 1", "Alternate Title 2")); + + // creation & publication dates + gemini.setDatasetReferenceDate(DatasetReferenceDate.builder() + .creationDate(LocalDate.of(2024, 1, 28)) + .publicationDate(LocalDate.of(2024, 9, 7)) + .build()); + + // observed properties + gemini.setObservedProperty(List.of( + ObservedProperty.builder().title("observed property 1").uri("https://example.com/op/1").unitsUri("https://example.com/units/m").units("metre").build(), + ObservedProperty.builder().value("observed property 2 value").build() + )); + + // keywords + gemini.setKeywordsPlace(List.of( + Keyword.builder().value("Lancaster").URI("https://example.com/lacaster").build(), + Keyword.builder().value("Bangor").URI("https://example.com/bangor").build() + )); + + // authors and points of contact + gemini.setResponsibleParties(List.of( + ResponsibleParty.builder().role("author").individualName("Donald").nameIdentifier("https://orcid.org/0000-1234-5678-9101").build(), + ResponsibleParty.builder().role("pointOfContact").organisationName("TMSP").organisationIdentifier("https://example.com/TMSP").build() + )); + + //when + val actual = template("rocrate/rocrate.ftl"); + log.info(actual); + + //then + JSONAssert.assertEquals(expected, actual, true); + verify(fileDetailsService).getDetailsFor(fileId, false); + } } } diff --git a/java/src/test/resources/templates/rocrate/attached-minimal.json b/java/src/test/resources/templates/rocrate/attached-minimal.json index 770e06135..9ad106326 100644 --- a/java/src/test/resources/templates/rocrate/attached-minimal.json +++ b/java/src/test/resources/templates/rocrate/attached-minimal.json @@ -22,7 +22,7 @@ "@id": "#eidc-dataCatalogue", "@type":"DataCatalog", "name":"Environmental Information Data Centre", - "alternatename":"EIDC", + "alternateName":"EIDC", "url":"https://catalogue.ceh.ac.uk/eidc/documents" }, { diff --git a/java/src/test/resources/templates/rocrate/full.json b/java/src/test/resources/templates/rocrate/full.json new file mode 100644 index 000000000..9e6580653 --- /dev/null +++ b/java/src/test/resources/templates/rocrate/full.json @@ -0,0 +1,124 @@ +{ + "@context": "https://w3id.org/ro/crate/1.1/context", + "@graph": [ + { + "@type": "CreativeWork", + "@id": "ro-crate-metadata.json", + "conformsTo": { + "@id": "https://w3id.org/ro/crate/1.1" + }, + "about": { + "@id": "https://example.org/id/882739943" + } + }, + { + "@type": "Dataset", + "name": "Title", + "@id": "https://example.org/id/882739943", + "hasPart": [ + { + "@id": "882739943" + }, + { + "@id": "882739943" + } + ], + "identifier": { + "@type": "PropertyValue", + "propertyID": "https://registry.identifiers.org/registry/doi", + "value": "doi:10.5285/882739943", + "url": "https://doi.org/10.5285/882739943" + }, + "url": "https://doi.org/10.5285/882739943", + "creditText": "Able, Bracken, Charles (2020). Title. Publisher. (Resource Type). https://doi.org/10.5285/882739943", + "description": "Description", + "alternateName": [ + "Alternate Title 1", + "Alternate Title 2" + ], + "isAccessibleForFree": true, + "dateCreated": "2024-01-28", + "datePublished": "2024-09-07", + "variableMeasured": [ + { + "@type": "StatisticalVariable", + "@id": "https://example.com/op/1", + "name": "observed property 1", + "unitCode": "https://example.com/units/m", + "unitText": "metre" + }, + "observed property 2 value" + ], + "keywords": [ + { + "@type": "DefinedTerm", + "@id": "https://example.com/bangor", + "name": "Bangor" + }, + { + "@type": "DefinedTerm", + "@id": "https://example.com/lacaster", + "name": "Lancaster" + } + ], + "author": [ + { + "@id": "https://orcid.org/0000-1234-5678-9101" + } + ], + "contactPoint": [ + { + "@id": "https://example.com/TMSP" + } + ], + "provider": { + "@id": "https://ror.org/04xw4m193" + }, + "includedInDataCatalog": { + "@id": "#eidc-dataCatalogue" + }, + "@context": "http://schema.org/" + }, + { + "@id": "#eidc-dataCatalogue", + "@type": "DataCatalog", + "name": "Environmental Information Data Centre", + "alternateName": "EIDC", + "url": "https://catalogue.ceh.ac.uk/eidc/documents" + }, + { + "@id": "https://ror.org/04xw4m193", + "@type": "Organization", + "name": "NERC EDS Environmental Information Data Centre", + "email": "info@eidc.ac.uk" + }, + { + "@id": "https://orcid.org/0000-1234-5678-9101", + "@type": "Person", + "name": "Donald", + "identifier": { + "@type": "PropertyValue", + "propertyID": "orcid", + "value": "https://orcid.org/0000-1234-5678-9101" + } + }, + { + "@id": "882739943", + "name": "882739943", + "@type": "File", + "encodingFormat": "text/csv", + "lastModified": "2024-12-09T15:34", + "bytes": 12, + "contentUrl": "https://example.com/name1" + }, + { + "@id": "882739943", + "name": "882739943", + "@type": "File", + "encodingFormat": "text/csv", + "lastModified": "2020-05-06T23:59", + "bytes": 9832, + "contentUrl": "https://example.com/name2" + } + ] +} diff --git a/java/src/test/resources/templates/rocrate/minimal.json b/java/src/test/resources/templates/rocrate/minimal.json index 770e06135..432736dcb 100644 --- a/java/src/test/resources/templates/rocrate/minimal.json +++ b/java/src/test/resources/templates/rocrate/minimal.json @@ -6,14 +6,14 @@ "@id": "ro-crate-metadata.json", "conformsTo": { "@id": "https://w3id.org/ro/crate/1.1" }, "about": { - "@id": "https://example.org/id/123456789" + "@id": "https://example.org/id/09837382" } }, { "@type":"Dataset", "name":"Title", - "@id": "https://example.org/id/123456789", - "url":"https://example.org/id/123456789", + "@id": "https://example.org/id/09837382", + "url":"https://example.org/id/09837382", "provider" : {"@id":"https://ror.org/04xw4m193"}, "includedInDataCatalog":{ "@id": "#eidc-dataCatalogue"}, "@context":"http://schema.org/" @@ -22,7 +22,7 @@ "@id": "#eidc-dataCatalogue", "@type":"DataCatalog", "name":"Environmental Information Data Centre", - "alternatename":"EIDC", + "alternateName":"EIDC", "url":"https://catalogue.ceh.ac.uk/eidc/documents" }, { diff --git a/templates/schema.org/_base.org.ftlh b/templates/schema.org/_base.org.ftlh index dfd1c9eef..ac598c74c 100644 --- a/templates/schema.org/_base.org.ftlh +++ b/templates/schema.org/_base.org.ftlh @@ -1,23 +1,3 @@ -<#import "../functions.ftlh" as func> - -<#if useConstraints?has_content> - <#assign licences = func.filter(useConstraints, "code", "license")> - -<#if onlineResources?has_content> - <#assign - infoLinks = func.filter(onlineResources, "function", "information") - > - - - <#--DE-DUPLICATE KEYWORD LIST --> - <#assign deDup = [] /> - <#list allKeywords as keywords> - <#if ! deDup?seq_contains(keywords)> - <#assign deDup = deDup + [keywords] /> - - - <#assign keywordList = deDup?sort_by("value")?sort_by("uri") /> - <#if type=='dataset' || type=='nonGeographicDataset' || type=='signpost'> <#assign docType = "Dataset"> <#elseif type=='aggregate' || type=='series'> @@ -27,77 +7,30 @@ <#macro schemaDocument showFiles=false> + <#if showFiles && docType == "Dataset"> + <#if isAttached!false> + <#assign parts = fileDetails.getDetailsFor(id, true)> + <#else> + <#assign parts = fileDetails.getDetailsFor(id, false)> + + { "@type":<@displayLiteral docType/>, "name":<@displayLiteral title/>, - - <#if showFiles> - <#if parts?? && parts?size gt 0> - <#if docType == "Dataset"> - "hasPart": [ - <#if isAttached!false> - <@partList fileDetails.getDetailsFor(id, true)/> - <#else> - <@partList fileDetails.getDetailsFor(id, false)/> - - ], - - - - "@id": "${uri?trim}", - <#if datacitable?string == "true" && citation?has_content> - "identifier": { - "@type":"PropertyValue", - "propertyID": "https://registry.identifiers.org/registry/doi", - "value": "doi:${citation.doi}", - "url": "${citation.url}" - }, - "url": "${citation.url}", - "creditText":"${citation.authors?join(', ')} (${citation.year?string["0000"]}). ${citation.title}. ${citation.publisher}. (${codes.lookup('datacite.resourceTypeGeneral',citation.resourceTypeGeneral)}). ${citation.url}", - <#else> - "url":"${uri?trim}", - - + <@partsList/> + <@datacite/> <#if resourceStatus != "Deleted"> - <#if description?has_content>"description":<@displayLiteral description/>, - - <#if alternateTitles?has_content> - "alternateName":[ - <#list alternateTitles as altTitle> - <@displayLiteral altTitle/><#sep>, - - ], - - - <#if resourceStatus == "Available"> - "isAccessibleForFree": true, - - - <#if datasetReferenceDate?? && datasetReferenceDate.creationDate?has_content> - "dateCreated":"${datasetReferenceDate.creationDate}", - - - <#if datasetReferenceDate?? && datasetReferenceDate.publicationDate?has_content> - "datePublished":"${datasetReferenceDate.publicationDate}", - - - <#if observedProperty?? && observedProperty?has_content> - "variableMeasured": [ <@observedPropertiesList observedProperty/>], - - - <#if keywordList?has_content> - "keywords": [<@keywordsList keywordList/>], - - - <#if authors?has_content> - "author": [<@contactList authors "author" />], - - - <#if pointsOfContact ?has_content> - "contactPoint": [<@contactList pointsOfContact />], - - + <#if description?has_content>"description":<@displayLiteral description/>, + <@alternateTitlesList/> + <#if resourceStatus == "Available">"isAccessibleForFree": true, + <@creationDate/> + <@publicationDate/> + <@observedPropertiesList/> + <@keywordsList/> + <#if authors?has_content>"author": [<@contactList authors "author" />], + <#if pointsOfContact?has_content>"contactPoint": [<@contactList pointsOfContact />], + <#-- Got to this point --> <#--Citations--> <#if incomingCitations?has_content> "@reverse": { @@ -164,9 +97,8 @@ "provider" : {"@id":"https://ror.org/04xw4m193"}, "includedInDataCatalog":{ "@id": "#eidc-dataCatalogue"}, - <#else> - <#-- information to include if the dataset has been permanently deleted --> + <#-- information to include if the dataset has been permanently deleted --> "description": "This resource is no longer available please contact the Environmental Information Data Centre for more details", "creativeWorkStatus": "Deleted", @@ -176,7 +108,7 @@ "@id": "#eidc-dataCatalogue", "@type":"DataCatalog", "name":"Environmental Information Data Centre", - "alternatename":"EIDC", + "alternateName":"EIDC", "url":"https://catalogue.ceh.ac.uk/eidc/documents" }, { @@ -220,16 +152,8 @@ ,<@fundDetails funding /> - <#if showFiles> - <#if parts?? && parts?size gt 0> - <#if docType == "Dataset"> - <#if isAttached!false> - ,<@partDetails fileDetails.getDetailsFor(id, true)/> - <#else> - ,<@partDetails fileDetails.getDetailsFor(id, false)/> - - - + <#if parts?? && parts?size gt 0> + ,<@partDetails parts/> <#if downloads?has_content> @@ -237,34 +161,80 @@ -<#macro keywordsList keywords> - <#list keywords as keyword> - <#if keyword.uri?has_content> - <#assign subjectScheme="" schemeURI=""> - <#if keyword.uri?matches("^http[s]?://inspire.ec.europa.eu/\\S+$")> - <#assign subjectScheme="European Union INSPIRE registry" schemeURI="http://inspire.ec.europa.eu/registry/"> - <#elseif keyword.uri?matches("^http[s]?://www.wikidata.org/entity/\\S+$")> - <#assign subjectScheme="Wikidata" schemeURI="https://www.wikidata.org/"> - <#elseif keyword.uri?matches("^http[s]?://sws.geonames.org/\\S+$")> - <#assign subjectScheme="Geonames" schemeURI="https://www.geonames.org/"> - <#elseif keyword.uri?matches("^http[s]?://www.eionet.europa.eu/gemet/concept/\\S+$")> - <#assign subjectScheme="GEMET concepts" schemeURI="https://www.eionet.europa.eu/gemet/"> +<#macro alternateTitlesList> + <#if alternateTitles??> + <#list alternateTitles> + "alternateName":[ + <#items as altTitle> + <@displayLiteral altTitle/><#sep>, + + ], + + + + +<#macro creationDate> + <#if datasetReferenceDate?? && datasetReferenceDate.creationDate?has_content> + "dateCreated":"${datasetReferenceDate.creationDate}", + + + +<#macro publicationDate> + <#if datasetReferenceDate?? && datasetReferenceDate.publicationDate?has_content> + "datePublished":"${datasetReferenceDate.publicationDate}", + + + +<#macro datacite> + <#if datacitable && citation?has_content> + "identifier": { + "@type":"PropertyValue", + "propertyID": "https://registry.identifiers.org/registry/doi", + "value": "doi:${citation.doi}", + "url": "${citation.url}" + }, + "url": "${citation.url}", + "creditText":"${citation.authors?join(', ')} (${citation.year?string["0000"]}). ${citation.title}. ${citation.publisher}. (${codes.lookup('datacite.resourceTypeGeneral',citation.resourceTypeGeneral)}). ${citation.url}", + <#else> + "url":"${uri?trim}", + + + +<#macro keywordsList> + <#if allKeywords??> + <#list allKeywords?sort_by("value")?sort_by("uri")> + "keywords": [ + <#items as keyword> + <#if keyword.uri?has_content> + <#assign subjectScheme="" schemeURI=""> + <#if keyword.uri?matches("^http[s]?://inspire.ec.europa.eu/\\S+$")> + <#assign subjectScheme="European Union INSPIRE registry" schemeURI="http://inspire.ec.europa.eu/registry/"> + <#elseif keyword.uri?matches("^http[s]?://www.wikidata.org/entity/\\S+$")> + <#assign subjectScheme="Wikidata" schemeURI="https://www.wikidata.org/"> + <#elseif keyword.uri?matches("^http[s]?://sws.geonames.org/\\S+$")> + <#assign subjectScheme="Geonames" schemeURI="https://www.geonames.org/"> + <#elseif keyword.uri?matches("^http[s]?://www.eionet.europa.eu/gemet/concept/\\S+$")> + <#assign subjectScheme="GEMET concepts" schemeURI="https://www.eionet.europa.eu/gemet/"> + + <#t>{ + <#t>"@type": "DefinedTerm", + <#t>"@id": "${keyword.uri?trim}", + <#t>"name": <@displayLiteral keyword.value/> + <#t><#if subjectScheme?has_content>,"inDefinedTermSet": "${schemeURI}" + } + <#else> + "${keyword.value?trim}" - <#t>{ - <#t>"@type": "DefinedTerm", - <#t>"@id": "${keyword.uri?trim}", - <#t>"name": <@displayLiteral keyword.value/> - <#t><#if subjectScheme?has_content>,"inDefinedTermSet": "${schemeURI}" - } - <#else> - "${keyword.value?trim}" - - <#sep>,<#t> + <#sep>, + ], + -<#macro observedPropertiesList props> - <#list props as op> +<#macro observedPropertiesList> +<#if observedProperty?? && observedProperty?has_content> +"variableMeasured": [ + <#list observedProperty as op> <#assign opLabel ="unknown"> <#if op.title?has_content> <#assign opLabel = op.title?trim> @@ -281,23 +251,29 @@ <#if op.units?has_content>,"unitText": "${op.units?trim}" } <#else> - <@displayLiteral opLabel/> + <@displayLiteral opLabel/> - <#sep>, + <#sep>, + ], + -<#macro partList parts> - <#if parts?size lt 60000> - <#list parts as part> - <#if part.id?has_content>{"@id": "${part.id}"} <#sep>, +<#macro partsList> + <#if parts?? && parts?size lt 60000> + <#list parts> + "hasPart": [ + <#items as part> + <#if part.id?has_content>{"@id": "${part.id}"}<#sep>, + + ], <#else> - {"@id": "${id}-files"} + {"@id": "${id}-files"}, -<#macro partDeails parts> +<#macro partDetails parts> <#if parts?size lt 60000> <#list parts as part> <#if part.id?has_content> From a484a44080920eac8d819413961dbb1e402364cb Mon Sep 17 00:00:00 2001 From: Rod Scott Date: Mon, 16 Dec 2024 15:25:15 +0000 Subject: [PATCH 7/7] RO-Crate & schema.org template refactoring Convert to macros to make the structure of the document easier to see. EMC-381 --- .../catalogue/gemini/GeminiDocument.java | 2 +- java/src/test/java/templates/RoCrateTest.java | 72 +++- .../test/java/templates/SchemaDotOrgTest.java | 69 ++++ .../templates/rocrate/attached-minimal.json | 57 ++- .../resources/templates/rocrate/full.json | 122 +++++- .../resources/templates/rocrate/minimal.json | 57 ++- .../templates/schemaDotOrg/minimal.json | 30 ++ templates/datacite/datacite.ftlx | 2 +- templates/html/elter.ftlh | 2 +- templates/html/gemini.ftlh | 2 +- templates/rdf/_macros.ftl | 4 - templates/rocrate/rocrate.ftl | 34 +- templates/rocrate/rocrate_attached.ftl | 13 +- .../schema.org/{_base.org.ftlh => macros.ftl} | 346 ++++++++---------- templates/schema.org/schema.org.ftl | 11 + templates/schema.org/schema.org.ftlh | 19 - 16 files changed, 557 insertions(+), 285 deletions(-) create mode 100644 java/src/test/java/templates/SchemaDotOrgTest.java create mode 100644 java/src/test/resources/templates/schemaDotOrg/minimal.json rename templates/schema.org/{_base.org.ftlh => macros.ftl} (62%) create mode 100644 templates/schema.org/schema.org.ftl delete mode 100644 templates/schema.org/schema.org.ftlh diff --git a/java/src/main/java/uk/ac/ceh/gateway/catalogue/gemini/GeminiDocument.java b/java/src/main/java/uk/ac/ceh/gateway/catalogue/gemini/GeminiDocument.java index eab50cd15..9e38d6180 100644 --- a/java/src/main/java/uk/ac/ceh/gateway/catalogue/gemini/GeminiDocument.java +++ b/java/src/main/java/uk/ac/ceh/gateway/catalogue/gemini/GeminiDocument.java @@ -38,7 +38,7 @@ @Template(called = "html/gemini.ftlh", whenRequestedAs = MediaType.TEXT_HTML_VALUE), @Template(called = "xml/gemini.ftlx", whenRequestedAs = GEMINI_XML_VALUE), @Template(called = "rdf/ttl.ftl", whenRequestedAs = RDF_TTL_VALUE), - @Template(called = "schema.org/schema.org.ftlh", whenRequestedAs = RDF_SCHEMAORG_VALUE), + @Template(called = "schema.org/schema.org.ftl", whenRequestedAs = RDF_SCHEMAORG_VALUE), @Template(called = "rocrate/rocrate.ftl", whenRequestedAs = ROCRATE_VALUE), @Template(called = "rocrate/rocrate_attached.ftl", whenRequestedAs = ROCRATE_ATTACHED_VALUE), @Template(called = "ceda/ceda.ftlh", whenRequestedAs = CEDA_YAML_VALUE) diff --git a/java/src/test/java/templates/RoCrateTest.java b/java/src/test/java/templates/RoCrateTest.java index 6bf7b83d0..95037ef57 100644 --- a/java/src/test/java/templates/RoCrateTest.java +++ b/java/src/test/java/templates/RoCrateTest.java @@ -15,12 +15,11 @@ import org.skyscreamer.jsonassert.JSONAssert; import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; import uk.ac.ceh.gateway.catalogue.citation.Citation; -import uk.ac.ceh.gateway.catalogue.gemini.AccessLimitation; -import uk.ac.ceh.gateway.catalogue.gemini.DatasetReferenceDate; -import uk.ac.ceh.gateway.catalogue.gemini.GeminiDocument; -import uk.ac.ceh.gateway.catalogue.gemini.Keyword; +import uk.ac.ceh.gateway.catalogue.gemini.*; +import uk.ac.ceh.gateway.catalogue.geometry.BoundingBox; import uk.ac.ceh.gateway.catalogue.model.ObservedProperty; import uk.ac.ceh.gateway.catalogue.model.ResponsibleParty; +import uk.ac.ceh.gateway.catalogue.model.Supplemental; import uk.ac.ceh.gateway.catalogue.templateHelpers.CodeLookupService; import uk.ac.ceh.gateway.catalogue.templateHelpers.FileDetailsService; @@ -51,7 +50,7 @@ private void givenCodeLookupService() { .willReturn("Resource Type"); } - private void givenFileDetailsService(String fileId) { + private void givenFileDetailsServiceDetached(String fileId) { given(fileDetailsService.getDetailsFor(fileId, false)) .willReturn(List.of( new FileDetailsService.Part(fileId, "File", "name1", "text/csv", "https://example.com/name1", 12L, LocalDateTime.of(2024,12,9,15, 34)), @@ -59,6 +58,14 @@ private void givenFileDetailsService(String fileId) { )); } + private void givenFileDetailsServiceAttached(String fileId) { + given(fileDetailsService.getDetailsFor(fileId, true)) + .willReturn(List.of( + new FileDetailsService.Part(fileId, "File", "name1", "text/csv", "data/name4", 542L, LocalDateTime.of(2024,12,9,15, 34)), + new FileDetailsService.Part(fileId, "File", "name2", "text/csv", "data/name5", 32L, LocalDateTime.of(2020,5,6,23, 59)) + )); + } + private GeminiDocument createGeminiDocument(String fileId) { val gemini = new GeminiDocument(); gemini.setUri("https://example.org/id/" + fileId); @@ -85,7 +92,7 @@ private String template(String templateFilename) { @SneakyThrows @BeforeEach void init() { - configuration = new Configuration(Configuration.VERSION_2_3_23); + configuration = new Configuration(Configuration.VERSION_2_3_33); configuration.setDirectoryForTemplateLoading(new File("../templates")); configuration.setSharedVariable("codes", codeLookupService); configuration.setSharedVariable("fileDetails", fileDetailsService); @@ -99,14 +106,17 @@ class Attached { @Test void rocrateAttachedMinimal() { //given - gemini = createGeminiDocument("123456789"); val expected = expected("rocrate/attached-minimal.json"); + val fileId = "123456789"; + gemini = createGeminiDocument(fileId); + givenFileDetailsServiceAttached(fileId); //when val actual = template("rocrate/rocrate_attached.ftl"); //then JSONAssert.assertEquals(expected, actual, true); + verify(fileDetailsService).getDetailsFor(fileId, true); } } @@ -118,14 +128,17 @@ class Detached { @Test void rocrateMinimal() { //given - gemini = createGeminiDocument("09837382"); val expected = expected("rocrate/minimal.json"); + val fileId = "09837382"; + gemini = createGeminiDocument(fileId); + givenFileDetailsServiceDetached(fileId); //when val actual = template("rocrate/rocrate.ftl"); //then JSONAssert.assertEquals(expected, actual, true); + verify(fileDetailsService).getDetailsFor(fileId, false); } @SneakyThrows @@ -138,7 +151,7 @@ void rocrateFull() { gemini = createGeminiDocument(fileId); // partsList & partDetails - givenFileDetailsService(fileId); + givenFileDetailsServiceDetached(fileId); // datacite givenCodeLookupService(); @@ -179,13 +192,48 @@ void rocrateFull() { // authors and points of contact gemini.setResponsibleParties(List.of( - ResponsibleParty.builder().role("author").individualName("Donald").nameIdentifier("https://orcid.org/0000-1234-5678-9101").build(), - ResponsibleParty.builder().role("pointOfContact").organisationName("TMSP").organisationIdentifier("https://example.com/TMSP").build() + ResponsibleParty.builder().role("author").individualName("Donald").email("donald@example.com").nameIdentifier("https://orcid.org/0000-1234-5678-9101").build(), + ResponsibleParty.builder().role("pointOfContact").organisationName("TMSP").email("pocs@example.com").organisationIdentifier("https://example.com/TMSP").build() + )); + + // incoming citations + gemini.setIncomingCitations(List.of( + Supplemental.builder().url("https://example.com/citations/0").description("description").build(), + Supplemental.builder().url("https://example.com/citations/1").build(), + Supplemental.builder().name("something else").build() + )); + + // temporal extents + gemini.setTemporalExtents(List.of( + TimePeriod.builder().begin("2024-02-01").end("2024-10-28").build(), + TimePeriod.builder().begin("2019-08-22").build(), + TimePeriod.builder().end("2018-11-30").build() + )); + + // bounding boxes + gemini.setBoundingBoxes(List.of( + BoundingBox.builder().northBoundLatitude("46.2").eastBoundLongitude("2.3").southBoundLatitude("45.7").westBoundLongitude("0.4").build(), + BoundingBox.builder().northBoundLatitude("36.8").eastBoundLongitude("48.7").southBoundLatitude("-11.6").westBoundLongitude("-120.5").build() + )); + + gemini.setFunding(List.of( + Funding.builder().funderName("UKRI").build(), + Funding.builder().funderName("University of Oxford").build() + )); + + // OGL licences + gemini.setUseConstraints(List.of( + ResourceConstraint.builder().code("license").uri("https://eidc.ceh.ac.uk/licences/OGL/plain").build() + )); + + // downloads + gemini.setOnlineResources(List.of( + OnlineResource.builder().function("download").url("https://example.com/download/0").build(), + OnlineResource.builder().function("order").url("https://example.com/order/1").build() )); //when val actual = template("rocrate/rocrate.ftl"); - log.info(actual); //then JSONAssert.assertEquals(expected, actual, true); diff --git a/java/src/test/java/templates/SchemaDotOrgTest.java b/java/src/test/java/templates/SchemaDotOrgTest.java new file mode 100644 index 000000000..332afb4f9 --- /dev/null +++ b/java/src/test/java/templates/SchemaDotOrgTest.java @@ -0,0 +1,69 @@ +package templates; + +import freemarker.template.Configuration; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.skyscreamer.jsonassert.JSONAssert; +import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; +import uk.ac.ceh.gateway.catalogue.gemini.GeminiDocument; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +@Slf4j +public class SchemaDotOrgTest { + + Configuration configuration; + GeminiDocument gemini; + + @SneakyThrows + private String expected(String filename) { + val expected = Objects.requireNonNull(getClass().getResourceAsStream(filename)); + return IOUtils.toString(expected, StandardCharsets.UTF_8); + } + + @SneakyThrows + private String template(String templateFilename) { + return FreeMarkerTemplateUtils.processTemplateIntoString( + configuration.getTemplate(templateFilename), + gemini + ); + } + + private GeminiDocument createGeminiDocument(String fileId) { + val gemini = new GeminiDocument(); + gemini.setUri("https://example.org/id/" + fileId); + gemini.setId(fileId); + gemini.setTitle("Title"); + gemini.setType("dataset"); + return gemini; + } + + @SneakyThrows + @BeforeEach + void init() { + configuration = new Configuration(Configuration.VERSION_2_3_33); + configuration.setDirectoryForTemplateLoading(new File("../templates")); + } + + @SneakyThrows + @Test + void schemaDotOrgMinimal() { + //given + val expected = expected("schemaDotOrg/minimal.json"); + val fileId = "123456789"; + gemini = createGeminiDocument(fileId); + + //when + val actual = template("schema.org/schema.org.ftl"); + log.info(actual); + + //then + JSONAssert.assertEquals(expected, actual, true); + } +} diff --git a/java/src/test/resources/templates/rocrate/attached-minimal.json b/java/src/test/resources/templates/rocrate/attached-minimal.json index 9ad106326..d237397fe 100644 --- a/java/src/test/resources/templates/rocrate/attached-minimal.json +++ b/java/src/test/resources/templates/rocrate/attached-minimal.json @@ -4,32 +4,63 @@ { "@type": "CreativeWork", "@id": "ro-crate-metadata.json", - "conformsTo": { "@id": "https://w3id.org/ro/crate/1.1" }, + "conformsTo": { + "@id": "https://w3id.org/ro/crate/1.1" + }, "about": { "@id": "https://example.org/id/123456789" } }, { - "@type":"Dataset", - "name":"Title", + "@type": "Dataset", + "name": "Title", "@id": "https://example.org/id/123456789", - "url":"https://example.org/id/123456789", - "provider" : {"@id":"https://ror.org/04xw4m193"}, - "includedInDataCatalog":{ "@id": "#eidc-dataCatalogue"}, - "@context":"http://schema.org/" + "hasPart": [ + { + "@id": "#part123456789" + }, + { + "@id": "#part123456789" + } + ], + "url": "https://example.org/id/123456789", + "provider": { + "@id": "https://ror.org/04xw4m193" + }, + "includedInDataCatalog": { + "@id": "#eidc-dataCatalogue" + } }, { "@id": "#eidc-dataCatalogue", - "@type":"DataCatalog", - "name":"Environmental Information Data Centre", - "alternateName":"EIDC", - "url":"https://catalogue.ceh.ac.uk/eidc/documents" + "@type": "DataCatalog", + "name": "Environmental Information Data Centre", + "alternateName": "EIDC", + "url": "https://catalogue.ceh.ac.uk/eidc/documents" }, { "@id": "https://ror.org/04xw4m193", - "@type":"Organization", - "name":"NERC EDS Environmental Information Data Centre", + "@type": "Organization", + "name": "NERC EDS Environmental Information Data Centre", "email": "info@eidc.ac.uk" + }, + { + "@id": "#part123456789", + "name": "123456789", + "@type": "File", + "encodingFormat": "text/csv", + "lastModified": "2024-12-09T15:34", + "bytes": 542, + "contentUrl": "data/name4" + }, + { + "@id": "#part123456789", + "name": "123456789", + "@type": "File", + "encodingFormat": "text/csv", + "lastModified": "2020-05-06T23:59", + "bytes": 32, + "contentUrl": "data/name5" } ] } diff --git a/java/src/test/resources/templates/rocrate/full.json b/java/src/test/resources/templates/rocrate/full.json index 9e6580653..db79ce43e 100644 --- a/java/src/test/resources/templates/rocrate/full.json +++ b/java/src/test/resources/templates/rocrate/full.json @@ -17,10 +17,10 @@ "@id": "https://example.org/id/882739943", "hasPart": [ { - "@id": "882739943" + "@id": "#part882739943" }, { - "@id": "882739943" + "@id": "#part882739943" } ], "identifier": { @@ -71,13 +71,57 @@ "@id": "https://example.com/TMSP" } ], + "@reverse": { + "citation": [ + { + "@id": "https://example.com/citations/0" + }, + { + "@id": "https://example.com/citations/1" + }, + { + "@id": "#citation2" + } + ] + }, + "temporalCoverage": [ + "2024-02-01/2024-10-28", + "2019-08-22/", + "/2018-11-30" + ], + "spatialCoverage": [ + { + "@id": "#bbox0" + }, + { + "@id": "#bbox1" + } + ], + "funder": [ + { + "@id": "#fund0" + }, + { + "@id": "#fund1" + } + ], + "license": { + "@id": "#oglLicence" + }, + "distribution": [ + { + "@id": "#distribution0" + }, + { + "@id": "#distribution1" + } + ], "provider": { "@id": "https://ror.org/04xw4m193" }, "includedInDataCatalog": { "@id": "#eidc-dataCatalogue" - }, - "@context": "http://schema.org/" + } }, { "@id": "#eidc-dataCatalogue", @@ -92,10 +136,34 @@ "name": "NERC EDS Environmental Information Data Centre", "email": "info@eidc.ac.uk" }, + { + "@id": "#oglLicence", + "@type": "CreativeWork", + "name": "Open Government Licence v3", + "alternateName": "OGL-UK-3.0", + "license": "https://spdx.org/licenses/OGL-UK-3.0.html" + }, + { + "@id": "#bbox0", + "@type": "Place", + "geo": { + "@type": "GeoShape", + "box": "0.4 45.7, 2.3 46.2" + } + }, + { + "@id": "#bbox1", + "@type": "Place", + "geo": { + "@type": "GeoShape", + "box": "-120.5 -11.6, 48.7 36.8" + } + }, { "@id": "https://orcid.org/0000-1234-5678-9101", "@type": "Person", "name": "Donald", + "email": "donald@example.com", "identifier": { "@type": "PropertyValue", "propertyID": "orcid", @@ -103,7 +171,39 @@ } }, { - "@id": "882739943", + "@id": "https://example.com/TMSP", + "@type": "Organization", + "name": "TMSP", + "email": "pocs@example.com", + "identifier": "https://example.com/TMSP" + }, + { + "@id": "https://example.com/citations/0", + "@type": "CreativeWork", + "creditText": "description", + "url": "https://example.com/citations/0" + }, + { + "@id": "https://example.com/citations/1", + "@type": "CreativeWork", + "url": "https://example.com/citations/1" + }, + { + "@id": "#citation2", + "@type": "CreativeWork" + }, + { + "@id": "#fund0", + "@type": "Organization", + "name": "UKRI" + }, + { + "@id": "#fund1", + "@type": "Organization", + "name": "University of Oxford" + }, + { + "@id": "#part882739943", "name": "882739943", "@type": "File", "encodingFormat": "text/csv", @@ -112,13 +212,23 @@ "contentUrl": "https://example.com/name1" }, { - "@id": "882739943", + "@id": "#part882739943", "name": "882739943", "@type": "File", "encodingFormat": "text/csv", "lastModified": "2020-05-06T23:59", "bytes": 9832, "contentUrl": "https://example.com/name2" + }, + { + "@id": "#distribution0", + "@type": "DataDownload", + "contentUrl": "https://example.com/download/0" + }, + { + "@id": "#distribution1", + "@type": "DataDownload", + "contentUrl": "https://example.com/order/1" } ] } diff --git a/java/src/test/resources/templates/rocrate/minimal.json b/java/src/test/resources/templates/rocrate/minimal.json index 432736dcb..db5e0de9c 100644 --- a/java/src/test/resources/templates/rocrate/minimal.json +++ b/java/src/test/resources/templates/rocrate/minimal.json @@ -4,32 +4,63 @@ { "@type": "CreativeWork", "@id": "ro-crate-metadata.json", - "conformsTo": { "@id": "https://w3id.org/ro/crate/1.1" }, + "conformsTo": { + "@id": "https://w3id.org/ro/crate/1.1" + }, "about": { "@id": "https://example.org/id/09837382" } }, { - "@type":"Dataset", - "name":"Title", + "@type": "Dataset", + "name": "Title", "@id": "https://example.org/id/09837382", - "url":"https://example.org/id/09837382", - "provider" : {"@id":"https://ror.org/04xw4m193"}, - "includedInDataCatalog":{ "@id": "#eidc-dataCatalogue"}, - "@context":"http://schema.org/" + "hasPart": [ + { + "@id": "#part09837382" + }, + { + "@id": "#part09837382" + } + ], + "url": "https://example.org/id/09837382", + "provider": { + "@id": "https://ror.org/04xw4m193" + }, + "includedInDataCatalog": { + "@id": "#eidc-dataCatalogue" + } }, { "@id": "#eidc-dataCatalogue", - "@type":"DataCatalog", - "name":"Environmental Information Data Centre", - "alternateName":"EIDC", - "url":"https://catalogue.ceh.ac.uk/eidc/documents" + "@type": "DataCatalog", + "name": "Environmental Information Data Centre", + "alternateName": "EIDC", + "url": "https://catalogue.ceh.ac.uk/eidc/documents" }, { "@id": "https://ror.org/04xw4m193", - "@type":"Organization", - "name":"NERC EDS Environmental Information Data Centre", + "@type": "Organization", + "name": "NERC EDS Environmental Information Data Centre", "email": "info@eidc.ac.uk" + }, + { + "@id": "#part09837382", + "name": "09837382", + "@type": "File", + "encodingFormat": "text/csv", + "lastModified": "2024-12-09T15:34", + "bytes": 12, + "contentUrl": "https://example.com/name1" + }, + { + "@id": "#part09837382", + "name": "09837382", + "@type": "File", + "encodingFormat": "text/csv", + "lastModified": "2020-05-06T23:59", + "bytes": 9832, + "contentUrl": "https://example.com/name2" } ] } diff --git a/java/src/test/resources/templates/schemaDotOrg/minimal.json b/java/src/test/resources/templates/schemaDotOrg/minimal.json new file mode 100644 index 000000000..cbbf8094a --- /dev/null +++ b/java/src/test/resources/templates/schemaDotOrg/minimal.json @@ -0,0 +1,30 @@ +{ + "@context": "http://schema.org/", + "@graph": [ + { + "@type": "Dataset", + "name": "Title", + "@id": "https://example.org/id/123456789", + "url": "https://example.org/id/123456789", + "provider": { + "@id": "https://ror.org/04xw4m193" + }, + "includedInDataCatalog": { + "@id": "#eidc-dataCatalogue" + } + }, + { + "@id": "#eidc-dataCatalogue", + "@type": "DataCatalog", + "name": "Environmental Information Data Centre", + "alternateName": "EIDC", + "url": "https://catalogue.ceh.ac.uk/eidc/documents" + }, + { + "@id": "https://ror.org/04xw4m193", + "@type": "Organization", + "name": "NERC EDS Environmental Information Data Centre", + "email": "info@eidc.ac.uk" + } + ] +} diff --git a/templates/datacite/datacite.ftlx b/templates/datacite/datacite.ftlx index a06e2071f..ff92c4a9b 100644 --- a/templates/datacite/datacite.ftlx +++ b/templates/datacite/datacite.ftlx @@ -1,4 +1,4 @@ -<#compress><#import "../functions.ftlh" as func> +<#compress> ${doi} diff --git a/templates/html/elter.ftlh b/templates/html/elter.ftlh index 4ea6303b4..441407694 100644 --- a/templates/html/elter.ftlh +++ b/templates/html/elter.ftlh @@ -159,7 +159,7 @@
diff --git a/templates/html/gemini.ftlh b/templates/html/gemini.ftlh index ebda854f6..186f06ec0 100644 --- a/templates/html/gemini.ftlh +++ b/templates/html/gemini.ftlh @@ -222,7 +222,7 @@ diff --git a/templates/rdf/_macros.ftl b/templates/rdf/_macros.ftl index 666a73fb0..dc05bf06c 100644 --- a/templates/rdf/_macros.ftl +++ b/templates/rdf/_macros.ftl @@ -1,8 +1,4 @@ -<#import "../functions.ftlh" as func> <#setting date_format = 'yyyy-MM-dd'> -<#if useConstraints?has_content> - <#assign licences = func.filter(useConstraints, "code", "license")> - <#macro displayLiteral string> <#--Ensure literals do not contain " characters or line breaks--> diff --git a/templates/rocrate/rocrate.ftl b/templates/rocrate/rocrate.ftl index 6be06f4a1..3b96a9746 100644 --- a/templates/rocrate/rocrate.ftl +++ b/templates/rocrate/rocrate.ftl @@ -1,27 +1,11 @@ <#compress> -<#include "../schema.org/_base.org.ftlh"> -<#if type=='dataset' || type=='nonGeographicDataset' || type=='signpost'> - <#assign docType = "Dataset"> -<#elseif type=='aggregate' || type=='series'> - <#assign docType = "Series"> -<#elseif type=='application'> - <#assign docType = "SoftwareSourceCode"> - - -<#if docType?has_content> - { - "@context": "https://w3id.org/ro/crate/1.1/context", - "@graph": [ - { - "@type": "CreativeWork", - "@id": "ro-crate-metadata.json", - "conformsTo": { "@id": "https://w3id.org/ro/crate/1.1" }, - "about": { - "@id": "${uri?trim}" - } - }, - <@schemaDocument showFiles=true/> - ] - } - + <#import "../schema.org/macros.ftl" as m> + <#if type=='dataset' || type=='nonGeographicDataset' || type=='signpost'> + <#assign docType = "Dataset"> + <#elseif type=='aggregate' || type=='series'> + <#assign docType = "Series"> + <#elseif type=='application'> + <#assign docType = "SoftwareSourceCode"> + + <@m.rocrate docType fileDetails.getDetailsFor(id, false)/> diff --git a/templates/rocrate/rocrate_attached.ftl b/templates/rocrate/rocrate_attached.ftl index cd3abef46..c18e39491 100644 --- a/templates/rocrate/rocrate_attached.ftl +++ b/templates/rocrate/rocrate_attached.ftl @@ -1,2 +1,11 @@ -<#assign isAttached=true> -<#include "rocrate.ftl"> +<#compress> + <#import "../schema.org/macros.ftl" as m> + <#if type=='dataset' || type=='nonGeographicDataset' || type=='signpost'> + <#assign docType = "Dataset"> + <#elseif type=='aggregate' || type=='series'> + <#assign docType = "Series"> + <#elseif type=='application'> + <#assign docType = "SoftwareSourceCode"> + + <@m.rocrate docType fileDetails.getDetailsFor(id, true)/> + diff --git a/templates/schema.org/_base.org.ftlh b/templates/schema.org/macros.ftl similarity index 62% rename from templates/schema.org/_base.org.ftlh rename to templates/schema.org/macros.ftl index ac598c74c..0b98cb8a9 100644 --- a/templates/schema.org/_base.org.ftlh +++ b/templates/schema.org/macros.ftl @@ -1,26 +1,41 @@ -<#if type=='dataset' || type=='nonGeographicDataset' || type=='signpost'> - <#assign docType = "Dataset"> -<#elseif type=='aggregate' || type=='series'> - <#assign docType = "Series"> -<#elseif type=='application'> - <#assign docType = "SoftwareSourceCode"> - +<#-- Top-level entry macros either 'rocrate' or 'schemaDotOrg' --> -<#macro schemaDocument showFiles=false> - <#if showFiles && docType == "Dataset"> - <#if isAttached!false> - <#assign parts = fileDetails.getDetailsFor(id, true)> - <#else> - <#assign parts = fileDetails.getDetailsFor(id, false)> - +<#macro rocrate docType="" parts=[]> + <#if docType?has_content> + { + "@context": "https://w3id.org/ro/crate/1.1/context", + "@graph": [ + { + "@type": "CreativeWork", + "@id": "ro-crate-metadata.json", + "conformsTo": { "@id": "https://w3id.org/ro/crate/1.1" }, + "about": { "@id": "${uri?trim}" } + }, + <@schemaDocument docType parts/> + ] + } + + +<#macro schemaDotOrg docType="", parts=[]> + <#if docType?has_content> + { + "@context":"http://schema.org/", + "@graph": [ + <@m.schemaDocument docType parts/> + ] + } + + + +<#macro schemaDocument docType parts> { "@type":<@displayLiteral docType/>, "name":<@displayLiteral title/>, "@id": "${uri?trim}", - <@partsList/> + <@partsList parts/> <@datacite/> - <#if resourceStatus != "Deleted"> + <#if resourceStatus?lower_case != "deleted"> <#if description?has_content>"description":<@displayLiteral description/>, <@alternateTitlesList/> <#if resourceStatus == "Available">"isAccessibleForFree": true, @@ -28,137 +43,46 @@ <@publicationDate/> <@observedPropertiesList/> <@keywordsList/> - <#if authors?has_content>"author": [<@contactList authors "author" />], - <#if pointsOfContact?has_content>"contactPoint": [<@contactList pointsOfContact />], - <#-- Got to this point --> - <#--Citations--> - <#if incomingCitations?has_content> - "@reverse": { - "citation":[ - <@citationList incomingCitations /> - ] - }, - - - <#if temporalExtents?has_content> - "temporalCoverage":[ - <#list temporalExtents as temporal> - <#if temporal.begin?has_content> - <#assign begin = temporal.begin> - <#else> - <#assign begin = ""> - - <#if temporal.end?has_content> - <#assign end = temporal.end> - <#else> - <#assign end = ""> - - "${begin}/${end}"<#sep>, - - ], - - - - <#if boundingBoxes?has_content> - "spatialCoverage": [ - <@itemList boundingBoxes "bbox"/> - ], - - - <#if funding?has_content> - "funder": [ - <@itemList funding "fund"/> - ], - - + <#if authors?has_content>"author": [<@contactList authors "author"/>], + <#if pointsOfContact?has_content>"contactPoint": [<@contactList pointsOfContact/>], + <@citationList/> + <@temporalExtentsList/> + <#if boundingBoxes?has_content>"spatialCoverage": [<@itemList boundingBoxes "bbox"/>], + <#if funding?has_content>"funder": [<@itemList funding "fund"/>], <#if docType == "Dataset" || docType == "SoftwareSourceCode"> - - <#if licences?? && licences?has_content> - <#if licences?first.uri?? && licences?first.uri?has_content> - <#if licences?first.uri?matches("^http[s]?://eidc.ceh.ac.uk/licences/OGL.+$")> - "license": {"@id": "oglLicence"}, - <#else> - "license": "${licences?first.uri?trim}", - - - - - <#if downloads?has_content> - "distribution": [<@itemList downloads "distribution" />], - - - <#if publishers?has_content> - <#assign publisher = publishers?first> - <#if publisher.organisationIdentifier?has_content> - "publisher":{"@id":"${publisher.organisationIdentifier}"}, - - + <@licencesLink/> + <#if downloads?has_content>"distribution": [<@itemList downloads "distribution" />], + <@publisherLink/> - "provider" : {"@id":"https://ror.org/04xw4m193"}, - "includedInDataCatalog":{ "@id": "#eidc-dataCatalogue"}, + "includedInDataCatalog":{ "@id": "#eidc-dataCatalogue"} <#else> <#-- information to include if the dataset has been permanently deleted --> "description": "This resource is no longer available please contact the Environmental Information Data Centre for more details", - "creativeWorkStatus": "Deleted", - - "@context":"http://schema.org/" - }, - { - "@id": "#eidc-dataCatalogue", - "@type":"DataCatalog", - "name":"Environmental Information Data Centre", - "alternateName":"EIDC", - "url":"https://catalogue.ceh.ac.uk/eidc/documents" - }, - { - "@id": "https://ror.org/04xw4m193", - "@type":"Organization", - "name":"NERC EDS Environmental Information Data Centre", - "email": "info@eidc.ac.uk" - } - - <#if licences?? && licences?has_content> - <#if licences?first.uri?? && licences?first.uri?has_content> - <#if licences?first.uri?matches("^http[s]?://eidc.ceh.ac.uk/licences/OGL.+$")> - ,{ - "@id": "oglLicence", - "@type": "CreativeWork", - "name": "Open Government Licence v3", - "alternateName":"OGL-UK-3.0", - "license": "https://spdx.org/licenses/OGL-UK-3.0.html" - } - - - - - <#if boundingBoxes?has_content> - ,<@bboxDetails boundingBoxes /> - - - <#if authors?has_content> - ,<@contactDetails authors "author" /> - - - <#if pocs?has_content> - ,<@contactDetails pocs /> - - - <#if incomingCitations?has_content> - ,<@citationDetails incomingCitations /> - - - <#if funding?has_content> - ,<@fundDetails funding /> - - - <#if parts?? && parts?size gt 0> - ,<@partDetails parts/> - - - <#if downloads?has_content> - ,<@distributionDetails downloads /> + "creativeWorkStatus": "Deleted" + }, + { + "@id": "#eidc-dataCatalogue", + "@type":"DataCatalog", + "name":"Environmental Information Data Centre", + "alternateName":"EIDC", + "url":"https://catalogue.ceh.ac.uk/eidc/documents" + }, + { + "@id": "https://ror.org/04xw4m193", + "@type":"Organization", + "name":"NERC EDS Environmental Information Data Centre", + "email": "info@eidc.ac.uk" + } + <@licencesDetail/> + <#if boundingBoxes?has_content>,<@bboxDetails/> + <#if authors?has_content>,<@contactDetails authors "author"/> + <#if pointsOfContact?has_content>,<@contactDetails pointsOfContact/> + <#if incomingCitations?has_content>,<@citationDetails/> + <#if funding?has_content>,<@fundDetails/> + <#if parts?has_content>,<@partDetails parts/> + <#if downloads?has_content>,<@distributionDetails/> <#macro alternateTitlesList> @@ -173,6 +97,19 @@ +<#macro bboxDetails> + <#list boundingBoxes as bbox> + { + "@id": "#bbox${bbox?index}", + "@type":"Place", + "geo":{ + "@type":"GeoShape", + "box":"${bbox.westBoundLongitude} ${bbox.southBoundLatitude}, ${bbox.eastBoundLongitude} ${bbox.northBoundLatitude}" + } + }<#sep>, + + + <#macro creationDate> <#if datasetReferenceDate?? && datasetReferenceDate.creationDate?has_content> "dateCreated":"${datasetReferenceDate.creationDate}", @@ -231,6 +168,34 @@ +<#macro licencesLink> + <#if licences?? && licences?has_content> + <#if licences?first.uri?? && licences?first.uri?has_content> + <#if licences?first.uri?matches("^http[s]?://eidc.ceh.ac.uk/licences/OGL/plain")> + "license": {"@id": "#oglLicence"}, + <#else> + "license": "${licences?first.uri?trim}", + + + + + +<#macro licencesDetail> + <#if licences?? && licences?has_content> + <#if licences?first.uri?? && licences?first.uri?has_content> + <#if licences?first.uri?matches("^http[s]?://eidc.ceh.ac.uk/licences/OGL.+$")> + ,{ + "@id": "#oglLicence", + "@type": "CreativeWork", + "name": "Open Government Licence v3", + "alternateName":"OGL-UK-3.0", + "license": "https://spdx.org/licenses/OGL-UK-3.0.html" + } + + + + + <#macro observedPropertiesList> <#if observedProperty?? && observedProperty?has_content> "variableMeasured": [ @@ -259,12 +224,12 @@ -<#macro partsList> - <#if parts?? && parts?size lt 60000> +<#macro partsList parts> + <#if parts?size lt 60000> <#list parts> "hasPart": [ <#items as part> - <#if part.id?has_content>{"@id": "${part.id}"}<#sep>, + <#if part.id?has_content>{"@id": "#part${part.id}"}<#sep>, ], @@ -278,7 +243,7 @@ <#list parts as part> <#if part.id?has_content> { - <#t>"@id": "${part.id}", + <#t>"@id": "#part${part.id}", <#t>"name": "${part.id}" <#if part.type?? && part.type?has_content><#t>,"@type": "${part.type}" <#if part.encodingFormat?? && part.encodingFormat?has_content>,<#t>"encodingFormat": "${part.encodingFormat}" @@ -299,10 +264,18 @@ +<#macro publisherLink> + <#if publishers?has_content> + <#assign publisher = publishers?first> + <#if publisher.organisationIdentifier?has_content> + "publisher":{"@id":"${publisher.organisationIdentifier}"}, + + + + <#macro itemList list idlabel="item"> <#list list as item> - <#assign itemid = "#" + idlabel + item?index> - {"@id": "${itemid}"}<#sep>, + {"@id": "#${idlabel}${item?index}"}<#sep>, @@ -334,7 +307,6 @@ <#assign contactid = contact.organisationIdentifier> - { "@id": "${contactid}", <#if contact.individualName?has_content> @@ -363,19 +335,25 @@ <#if contact.email?has_content>,"email": "${contact.email}" <#if contact.organisationIdentifier?has_content>,"identifier":"${contact.organisationIdentifier}" - }<#sep>, + }<#sep>, -<#macro citationList citations> - <#list incomingCitations as citation> - <#assign citationid = "#citation" + citation?index> - <#if citation.url?has_content><#assign citationid = citation.url> - {"@id": "${citationid}"}<#sep>, - +<#macro citationList> + <#if incomingCitations?has_content> + "@reverse": { + "citation":[ + <#list incomingCitations as citation> + <#assign citationid = "#citation" + citation?index> + <#if citation.url?has_content><#assign citationid = citation.url> + {"@id": "${citationid}"}<#sep>, + + ] + }, + -<#macro citationDetails citations> +<#macro citationDetails> <#list incomingCitations as citation> <#assign citationid = "#citation" + citation?index> <#if citation.url?has_content><#assign citationid = citation.url> @@ -384,48 +362,32 @@ "@type": "CreativeWork" <#if citation.description?has_content>,"creditText": <@displayLiteral citation.description/> <#if citation.url?has_content>,"url": "${citation.url?trim}" - }<#sep>, + }<#sep>, -<#macro bboxDetails boundingBoxes> - <#list boundingBoxes as bbox> - <#assign bboxid = "#bbox" + bbox?index> - { - "@id": "${bboxid}", - "@type":"Place", - "geo":{ - "@type":"GeoShape", - "box":"${bbox.westBoundLongitude} ${bbox.southBoundLatitude}, ${bbox.eastBoundLongitude} ${bbox.northBoundLatitude}" - } - }<#sep>, - - - -<#macro distributionDetails distributions> +<#macro distributionDetails> <#list downloads as distribution> - <#assign distributionid = "#distribution" + distribution?index> { - "@id": "${distributionid}", - "@type":"DataDownload", - "contentUrl":"${distribution.url}" - <#if distribution.url?ends_with(".zip")>,"encodingFormat":"application/zip" - <#elseif distribution.url?ends_with(".csv")>,"encodingFormat":"text/csv" - <#elseif distribution.url?starts_with("https://data-package.ceh.ac.uk/data/")>,"encodingFormat":"application/zip" - <#elseif distribution.url?starts_with("https://catalogue.ceh.ac.uk/datastore")>,"encodingFormat":"text/directory" - - }<#sep>, + "@id": "#distribution${distribution?index}", + "@type":"DataDownload", + "contentUrl":"${distribution.url}" + <#if distribution.url?ends_with(".zip")>,"encodingFormat":"application/zip" + <#elseif distribution.url?ends_with(".csv")>,"encodingFormat":"text/csv" + <#elseif distribution.url?starts_with("https://data-package.ceh.ac.uk/data/")>,"encodingFormat":"application/zip" + <#elseif distribution.url?starts_with("https://catalogue.ceh.ac.uk/datastore")>,"encodingFormat":"text/directory" + + }<#sep>, -<#macro fundDetails funding> +<#macro fundDetails> <#list funding as fund> - <#assign fundid = "#fund" + fund?index> { - "@id": "${fundid}", - "@type":"Organization" - <#if fund.funderName?? && fund.funderName?has_content>,<#t>"name":"${fund.funderName}" - }<#sep>, + "@id": "#fund${fund?index}", + "@type":"Organization" + <#if fund.funderName?? && fund.funderName?has_content>,<#t>"name":"${fund.funderName}" + }<#sep>, @@ -433,3 +395,13 @@ <#--Ensure literals do not contain " characters or line breaks--> <#t>"${string?trim?replace("\"","'")?replace("\n"," ")}" + +<#macro temporalExtentsList> + <#if temporalExtents?has_content> + "temporalCoverage":[ + <#list temporalExtents as temporal> + "${temporal.begin!""}/${temporal.end!""}"<#sep>, + + ], + + diff --git a/templates/schema.org/schema.org.ftl b/templates/schema.org/schema.org.ftl new file mode 100644 index 000000000..744e04285 --- /dev/null +++ b/templates/schema.org/schema.org.ftl @@ -0,0 +1,11 @@ +<#compress> + <#import "macros.ftl" as m> + <#if type=='dataset' || type=='nonGeographicDataset' || type=='signpost'> + <#assign docType = "Dataset"> + <#elseif type=='aggregate' || type=='series'> + <#assign docType = "Series"> + <#elseif type=='application'> + <#assign docType = "SoftwareSourceCode"> + + <@m.schemaDotOrg docType/> + diff --git a/templates/schema.org/schema.org.ftlh b/templates/schema.org/schema.org.ftlh deleted file mode 100644 index 63b77ea65..000000000 --- a/templates/schema.org/schema.org.ftlh +++ /dev/null @@ -1,19 +0,0 @@ -<#compress> -<#include "../schema.org/_base.org.ftlh"> - -<#if type=='dataset' || type=='nonGeographicDataset' || type=='signpost'> - <#assign docType = "Dataset"> -<#elseif type=='aggregate' || type=='series'> - <#assign docType = "Series"> -<#elseif type=='application'> - <#assign docType = "SoftwareSourceCode"> - - -<#if docType?has_content> - { - "@graph": [ - <@schemaDocument /> - ] - } - -