(setq org-babel-python-command "/home/grotec/.local/share/mamba/envs/rdf/bin/python")from oaipmh_scythe import Scythe
from bs4 import BeautifulSoup
from rdflib import Graph, Namespace, URIRef, Literal, BNode, FOAF, DC, XSD, RDF, RDFS
def parse_person(graph, person):
orcid = person.find('nameIdentifier', attrs={'nameIdentifierScheme':'ORCID'})
# Parse given name
given_name = person.find('givenName')
if given_name is not None:
given_name = given_name.string
else:
given_name = ""
# Parse family name
family_name = person.find('familyName')
if family_name is not None:
family_name = family_name.string
else:
family_name = ""
name = given_name + " " + family_name
if name == " ": name = "NN"
if orcid is None:
try:
person_uri = next(graph.subjects(predicate=RDFS.label, object=Literal(name)))
except StopIteration:
person_uri = BNode()
except:
raise
else:
person_uri = ORCID[orcid.string]
graph.add((person_uri, DCITE.identifier, Literal(person_uri, datatype=XSD.anyURI)))
graph.add((person_uri, RDF.type, FOAF.Person))
graph.add((person_uri, RDFS.label, Literal(name)))
graph.add((person_uri, DCITE.givenName, Literal(given_name)))
graph.add((person_uri, DCITE.familyName, Literal(family_name)))
# Get affiliations.
# Skip nfdi4bioimage because it's not an affiliation in the legal sense.
affiliations = (aff for aff in person.find_all('affiliation') if not aff.get('affiliationIdentifier', "").split('/')[-1] == '01vnkaz16')
for affiliation in affiliations:
graph, affiliation_ref = parse_institution(graph, affiliation)
graph.add((person_uri, DCITE.affiliation, affiliation_ref))
return graph, person_uri
def parse_institution(graph, institution):
""" Parse identifier and name of (academic) institution """
identifier = institution.get('affiliationIdentifier', None)
# If no identifier, return blank node with only the name.
if identifier is None:
# Identify institution by name string.
predicate = RDFS.label
object = Literal(institution.string)
# First see if this institution is already in the graph
try:
bn = next(graph.subjects(predicate=predicate, object=object))
except StopIteration: # not found, create it
bn = BNode()
graph.add((bn, RDFS.label, Literal(institution.string)))
graph.add((bn, RDF.type, OBI['0000245']))
except:
raise
return graph, bn
# If we have an id, get its scheme, too.
identifier_scheme = institution.get('affiliationIdentifierScheme')
# Handle ROR
if identifier_scheme == "ROR":
ror_uri = URIRef(identifier)
graph.add((ror_uri, RDF.type, OBI['0000245']))
graph.add((ror_uri, RDFS.label, Literal(institution.string)))
graph.add((ror_uri, DCITE.identifier, Literal(identifier, datatype=XSD.anyURI)))
return graph, ror_uri
# If not a ROR, return blank node with name and id as string.
# But first check if institution with this identifier already exists
try:
bn = next(graph.subjects(predicate=DCITE.identifier, object=Literal(identifier)))
except StopIteration:
bn = BNode()
graph.add((bn, RDFS.label, Literal(institution.string)))
graph.add((bn, DCITE.identifier, Literal(identifier)))
graph.add((bn, RDF.type, OBI['0000245']))
except:
raise
return graph, bn
def parse_date(date):
date_type = date.get('dateType')
return DCITE[date_type], Literal(date.string, datatype=XSD.date)
def parse_relation(relation):
rel_id_tpe = relation.get('relatedIdentifierType')
rel_tpe = relation.get('relationType')
if rel_id_tpe == "URL":
return DCITE[rel_tpe], URIRef(relation.string)
else:
return DCITE[rel_tpe], ns_dict[rel_id_tpe.lower()][relation.string]
# Init graph.
graph = Graph(bind_namespaces='rdflib')
# Namespaces and prefixes.
ns_dict = dict([
("datacite", DCITE := Namespace("https://schema.datacite.org/meta/kernel-4.6/metadata.xsd#")),
("nfdicore", NFDI := Namespace("https://nfdi.fiz-karlsruhe.de/ontology/")),
("orcid" , ORCID := Namespace("https://orcid.org/")),
("ror" , ROR := Namespace("https://ror.org/")),
("doi" , DOI := Namespace("https://doi.org/")),
("obi" , OBI := Namespace("http://purl.obolibrary.org/obo/OBI_")),
("t4fs" , T4FS := Namespace("http://purl.obolibrary.org/obo/T4FS_")),
("sio" , SIO := Namespace("http://semanticscience.org/resource/")),
])
for prefix, ns in ns_dict.items():
graph.bind(prefix, ns)
# Add core information about NFDI4BIOIMAGE.
n4bi = URIRef("https://nfdi4bioimage.de/rdf/node")
n4bicomm = URIRef("https://zenodo.org/communities/nfdi4bioimage")
graph.add((n4bi , NFDI.NFDI_0000195, n4bicomm)) # We have a collection aka zenodo community.
graph.add((n4bicomm , DC.identifier, Literal('nfdi4bioimage'))) # Our collection has an identifier ...
graph.add((n4bicomm , NFDI.NFDI_0001008, Literal('https://zenodo.org/communities/nfdi4bioimage'))) # ... and a website.
# Harvest the zenodo OAI-PMH API endpoint.
with Scythe("https://zenodo.org/oai2d") as scythe:
records = scythe.list_records(set_='user-nfdi4bioimage', metadata_prefix='oai_datacite')
# `records` is a list of xml strings.
# Loop over all records.
for i, rec0 in enumerate(records):
# Get a proper navigable xml object.
xml_root = BeautifulSoup(str(rec0), 'xml').find('resource')
# Get the record's DOI.
doi = xml_root.find('identifier', attrs={"identifierType":"DOI"})
# The record's DOI is the subject for most of the triples to be constructed.
subj = URIRef("https://doi.org/"+doi.string)
# Add record as part of community.
graph.add((n4bicomm, SIO.SIO_000088, subj))
# Get creators and contributors.
title = xml_root.find('title')
description = xml_root.find('description')
resource_type = xml_root.find('resourceType')
subjects = xml_root.find_all('subject')
rights = xml_root.find_all('rights')
creators = xml_root.find_all('creator')
contributors = xml_root.find_all('contributor')
affiliations = xml_root.find_all('affiliation')
relations = xml_root.find_all('relatedIdentifier')
dates = xml_root.find_all('date')
graph.add((subj, RDF.type, T4FS['0000113']))
graph.add((subj, DCITE.title, Literal(title.string)))
if description is not None:
graph.add((subj, DCITE.description, Literal(description.string)))
if resource_type is not None:
graph.add((subj, DCITE.resourceType, Literal(resource_type.string)))
for subject in subjects:
graph.add((subj, DCITE['subject'], Literal(subject.string)))
for right in rights:
graph.add((subj, DCITE['right'], Literal(right.string)))
for creator in creators:
graph, person = parse_person(graph, creator)
graph.add((subj, DCITE.creator, person))
for contributor in contributors:
graph, person = parse_person(graph, contributor)
graph.add((subj, DCITE.contributor, person))
for date in dates:
property, val = parse_date(date)
graph.add((subj, property, val))
for relation in relations:
property, val = parse_relation(relation)
graph.add((subj, property, val))
graph.serialize('../RDF_dumps/N4BI_zenodo_community.n3')
print(len(graph))Cleanup:
JAVA=$(which java)
export JAVA_HOME=/usr
echo $JAVA
echo $JAVA_HOME
RIOT=/opt/apache-jena/bin/riot
cat n4bi_zenodo_community.n3 | sed 's/^-\{2,\}.*$//' > tmp.n3
$RIOT --output n3 N4BI_zenodo_community.n3 > tmp.n3
$RIOT --output turtle tmp.n3 > N4BI_zenodo_community.ttl
mv tmp.n3 N4BI_zenodo_community.n3drop graph <https://kg.nfdi4bioimage.de/n4bikg/n4bi_zenodo_community>| HTTP/1.1 400 Bad Request | ||
|---|---|---|
| Server: nginx/1.22.1 | ||
| Date: Thu | 04 Jun 2026 11:51:15 GMT | |
| Content-Length: 0 | ||
| Connection: keep-alive | ||
| Cache-Control: must-revalidate | no-cache | no-store |
curl -L https://redefer.rhizomik.net/xsd2owl?xsd=https://schema.datacite.org/meta/kernel-4.6/metadata.xsd > datacite.owl.rdf.xmlexport PATH=/opt/apache-jena-5.2.0/bin:$PATH
echo """
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix dcite: <https://schema.datacite.org/meta/kernel-4.6/metadata.xsd#>
select distinct ?prop where {
?prop a ?tp .
values ?tp {owl:DatatypeProperty owl:ObjectProperty}
}
order by ?prop
""" > query.rq
arq --data=datacite.owl.rdf.xml --query=query.rq
from oaipmh_scythe import Scythe
from bs4 import BeautifulSoup
from rdflib import Graph, Namespace, URIRef, Literal, FOAF, DC
with Scythe("https://zenodo.org/oai2d") as scythe:
record = scythe. list_records(set_='user-nfdi4bioimage', metadata_prefix='oai_datacite')from oaipmh_scythe import Scythe
import pprint
with Scythe("https://zenodo.org/oai2d") as scythe:
records = scythe.list_records(set_='user-nfdi4bioimage', metadata_prefix='oai_datacite')
rec0 = next(records)
for key, val in rec0.metadata.items():
print(key, val)
print(rec0.xml)
from oaipmh_scythe import Scythe
from rdflib import Graph, BNode, Literal, URIRef, DC, FOAF, XSD, RDF, RDFS, Namespace
SIO = Namespace('http://semanticscience.org/resource/')
ZND = Namespace('https://zenodo.org/')
zenodo = Namespace('https://zenodo.org/ns/')
def add_persons(graph, person_list, property_term):
for c in person_list:
bn = BNode()
name_str = c.split(", ")
if len(name_str) > 1:
last = name_str[0]
first = ", ".join(name_str[1:])
graph.add((bn, FOAF.firstName, Literal(first)))
graph.add((bn, FOAF.lastName, Literal(last)))
else:
graph.add((bn, FOAF.name, Literal(name_str)))
graph.add((subject, property_term, bn))
return graph
g = Graph(bind_namespaces='rdflib')
g.bind("sio", SIO)
g.bind("znd", ZND)
g.bind("zenodo", zenodo)
n4bi = URIRef("https://nfdi4bioimage.de/rdf/node")
n4bicomm = URIRef("https://zenodo.org/communities/nfdi4bioimage")
g.add((n4bi, zenodo.community, n4bicomm))
g.add((n4bicomm, RDF.type, SIO.SIO_001064))
g.add((n4bicomm, DC.identifier, Literal('user-nfdi4bioimage')))
g.add((n4bicomm, SIO.SIO_000296, Literal('https://zenodo.org/communities/nfdi4bioimage')))
with Scythe("https://zenodo.org/oai2d") as scythe:
records = scythe.list_records(set_='user-nfdi4bioimage')
for rec0 in records:
creator = rec0.metadata.get('creator', [])
date = rec0.metadata.get('date', [])
description = rec0.metadata.get('description', [])
identifier = rec0.metadata.get('identifier', [])
publisher = rec0.metadata.get('publisher', [])
relation = rec0.metadata.get('relation', [])
rights = rec0.metadata.get('rights', [])
subjects = rec0.metadata.get('subject', [])
title = rec0.metadata.get('title', [])
tpe = rec0.metadata.get('type', [])
subject = URIRef(rec0.metadata['identifier'][0])
g.add((n4bicomm, SIO.SIO_000088, subject))
g = add_persons(g, contributor, DC.contributor)
g = add_persons(g, creator, DC.creator)
for p in publisher:
g.add((subject, DC.publisher, Literal(p)))
for dt in date:
g.add((subject, DC.date, Literal(dt, datatype=XSD.date)))
for desc in description:
g.add((subject, DC.description, Literal(desc)))
for right in rights:
g.add((subject, DC.rights, Literal(right)))
for sbjct in subjects:
g.add((subject, DC.subject, Literal(sbjct)))
for t in title:
g.add((subject, DC.title, Literal(t)))
for rel in relation:
g.add((subject, DC.relation, URIRef(rel)))
for id in identifier:
g.add((subject, DC.identifier, URIRef(id)))
for tp in tpe:
g.add((subject, DC.type, Literal(tp)))
g.serialize("/home/grotec/Repositories/NFDI4BI-KG/N4BI_zenodo_community.n3")