Skip to content

Commit 71a3dee

Browse files
committed
Fixed JSON output
1 parent fb50b69 commit 71a3dee

File tree

5 files changed

+86
-56
lines changed

5 files changed

+86
-56
lines changed

app/fdo_config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
Configuration and static data structures for the MaRDI FDO Server.
33
"""
44

5+
ENTITY_IRI = "https://portal.mardi4nfdi.de/entity/"
6+
FDO_IRI = "https://fdo.portal.mardi4nfdi.de/fdo/"
7+
FDO_ACCESS_IRI = "https://fdo.portal.mardi4nfdi.de/access/"
8+
59
# Maps Wikibase QIDs to internal/schema.org type strings.
610
QID_TYPE_MAP = {
711
"Q56887": "schema:ScholarlyArticle",

app/mardi_fdo_server.py

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@
99
from fastapi import FastAPI, HTTPException, Response
1010
from fastapi.responses import HTMLResponse
1111
from fastapi.staticfiles import StaticFiles
12-
from app.mardi_item_helper import BASE_IRI
13-
from fdo_schemas.publication import build_scholarly_article_payload
12+
from fdo_schemas.publication import build_scholarly_article_profile
1413
from fdo_schemas.person import build_author_payload
1514

1615
MW_API = "https://portal.mardi4nfdi.de/w/api.php"
17-
from app.fdo_config import QID_TYPE_MAP, JSONLD_CONTEXT
16+
from app.fdo_config import QID_TYPE_MAP, JSONLD_CONTEXT, FDO_IRI, FDO_ACCESS_IRI, ENTITY_IRI
1817

1918
app = FastAPI(
2019
title="MaRDI FDO façade",
@@ -92,26 +91,47 @@ def to_fdo(qid: str, entity: Dict[str, Any]) -> Dict[str, Any]:
9291

9392

9493
def to_fdo_publication(qid: str, entity: Dict[str, Any]) -> Dict[str, Any]:
95-
"""Return a schema.org ScholarlyArticle-styled FDO payload.
9694

97-
Args:
98-
qid: Identifier of the publication.
99-
entity: Raw entity JSON.
95+
fdo_id = f"{FDO_IRI}{qid}"
96+
access_id = f"{FDO_ACCESS_IRI}{qid}"
97+
98+
created = entity.get("created")
99+
modified = entity.get("modified")
100+
created_or_modified = created if created else modified if modified else ""
100101

101-
Returns:
102-
``FDOResponse`` enriched with schema.org publication fields.
103-
"""
104102
return {
105-
"@context": JSONLD_CONTEXT,
106-
"@id": BASE_IRI + qid,
107-
"@type": "schema:ScholarlyArticle",
108-
"kernel": build_scholarly_article_payload(qid, entity),
103+
"@context": [
104+
"https://w3id.org/fdo/context/v1",
105+
{
106+
"schema": "https://schema.org/",
107+
"prov": "http://www.w3.org/ns/prov#",
108+
"fdo": "https://w3id.org/fdo/vocabulary/"
109+
}
110+
],
111+
112+
"@id": fdo_id,
113+
"@type": "DigitalObject",
114+
115+
"kernel": {
116+
"@id": fdo_id,
117+
"digitalObjectType": "https://types.mardi4nfdi.de/ScholarlyArticle/v1",
118+
"created": created_or_modified,
119+
"modified": modified or "",
120+
"access": [{"@id": access_id}]
121+
},
122+
123+
"profile": build_scholarly_article_profile(qid, entity),
124+
109125
"access": {
110-
"accessURL": f"{BASE_IRI}{qid}",
111-
"mediaType": "application/ld+json",
126+
"@id": access_id,
127+
"accessURL": f"{fdo_id}?format=jsonld",
128+
"mediaType": "application/ld+json"
112129
},
113-
"prov:generatedAtTime": entity.get("modified", ""),
114-
"prov:wasAttributedTo": "MaRDI Knowledge Graph",
130+
131+
"provenance": {
132+
"prov:generatedAtTime": modified or "",
133+
"prov:wasAttributedTo": "MaRDI Knowledge Graph"
134+
}
115135
}
116136

117137

@@ -127,11 +147,11 @@ def to_fdo_author(qid: str, entity: Dict[str, Any]) -> Dict[str, Any]:
127147
"""
128148
return {
129149
"@context": JSONLD_CONTEXT,
130-
"@id": BASE_IRI + qid,
150+
"@id": ENTITY_IRI + qid,
131151
"@type": "schema:Person",
132152
"kernel": build_author_payload(qid, entity),
133153
"access": {
134-
"accessURL": f"{BASE_IRI}{qid}",
154+
"accessURL": f"{ENTITY_IRI}{qid}",
135155
"mediaType": "application/ld+json",
136156
},
137157
"prov:generatedAtTime": entity.get("modified", ""),
@@ -154,15 +174,15 @@ def to_fdo_minimal(qid: str, entity: Dict[str, Any]) -> Dict[str, Any]:
154174
entity_type = guess_type_from_claims(entity.get("claims", {}))
155175
return {
156176
"@context": JSONLD_CONTEXT,
157-
"@id": BASE_IRI + qid,
177+
"@id": ENTITY_IRI + qid,
158178
"@type": entity_type,
159179
"kernel": {
160180
"@type": entity_type,
161181
"name": label,
162182
"description": description,
163183
},
164184
"access": {
165-
"accessURL": f"{BASE_IRI}{qid}",
185+
"accessURL": f"{ENTITY_IRI}{qid}",
166186
"mediaType": "application/vnd.mardi.entity+json",
167187
},
168188
"prov:generatedAtTime": entity.get("modified", ""),

app/mardi_item_helper.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from typing import Any, Dict, List, Optional
66

7-
BASE_IRI = "https://portal.mardi4nfdi.de/entity/"
7+
from app.fdo_config import ENTITY_IRI
88

99

1010
def extract_item_ids(claims: Dict[str, Any], prop: str) -> List[str]:
@@ -77,4 +77,4 @@ def schema_refs_from_ids(ids: List[str]) -> List[Dict[str, str]]:
7777
Returns:
7878
List of dictionaries with ``@id`` references.
7979
"""
80-
return [{"@id": BASE_IRI + _id} for _id in ids]
80+
return [{"@id": ENTITY_IRI + _id} for _id in ids]

fdo_schemas/person.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
"""
55

66
from typing import Any, Dict, List, Optional
7+
8+
from app.fdo_config import ENTITY_IRI
79
from app.mardi_item_helper import (
8-
BASE_IRI,
910
extract_item_ids,
1011
extract_string_claim,
1112
schema_refs_from_ids,
@@ -23,17 +24,17 @@ def build_author_payload(qid: str, entity: Dict[str, Any]) -> Dict[str, Any]:
2324

2425
# Note: Property IDs here are provisional and should be verified against the MaRDI Wikibase
2526

26-
affiliation_ids = extract_item_ids(claims, "P1416") # Affiliation
27-
website = extract_string_claim(claims, "P856") # Official website
28-
orcid = extract_string_claim(claims, "P496") # ORCID iD
27+
affiliation_ids = extract_item_ids(claims, "P17") # Affiliation / Employer
28+
website = extract_string_claim(claims, "P29") # Official website
29+
orcid = extract_string_claim(claims, "P20") # ORCID iD
2930

3031
author: Dict[str, Any] = {
3132
"@context": "https://schema.org",
3233
"@type": "Person",
33-
"@id": BASE_IRI + qid,
34+
"@id": ENTITY_IRI + qid,
3435
"name": label,
3536
"description": description,
36-
"url": BASE_IRI + qid,
37+
"url": ENTITY_IRI + qid,
3738
}
3839

3940
if affiliation_ids:

fdo_schemas/publication.py

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44

55
from typing import Any, Dict, List, Optional
66

7+
from app.fdo_config import ENTITY_IRI
78
from app.mardi_item_helper import (
8-
BASE_IRI,
99
extract_item_ids,
1010
extract_string_claim,
1111
extract_time_claim,
1212
schema_refs_from_ids,
1313
)
1414

1515

16-
def build_scholarly_article_payload(qid: str, entity: Dict[str, Any]) -> Dict[str, Any]:
17-
"""Construct schema.org ScholarlyArticle JSON-LD from a Wikibase entity."""
16+
def build_scholarly_article_profile(qid: str, entity: Dict[str, Any]) -> Dict[str, Any]:
17+
1818
label = entity.get("labels", {}).get("en", {}).get("value", qid)
1919
description = entity.get("descriptions", {}).get("en", {}).get("value", "")
2020
claims = entity.get("claims", {})
@@ -33,52 +33,57 @@ def build_scholarly_article_payload(qid: str, entity: Dict[str, Any]) -> Dict[st
3333
page_range = extract_string_claim(claims, "P304")
3434
comment = extract_string_claim(claims, "P1448")
3535

36-
page_start: Optional[str] = None
37-
page_end: Optional[str] = None
36+
page_start, page_end = None, None
3837
if page_range and "-" in page_range:
39-
parts = page_range.split("-", maxsplit=1)
40-
page_start, page_end = parts[0], parts[1]
38+
page_start, page_end = page_range.split("-", maxsplit=1)
4139

42-
article: Dict[str, Any] = {
40+
profile = {
4341
"@context": "https://schema.org",
4442
"@type": "ScholarlyArticle",
45-
"@id": BASE_IRI + qid,
43+
44+
# Schema.org identity stays in the Wikibase namespace
45+
"@id": f"{ENTITY_IRI}{qid}",
4646
"name": label,
4747
"headline": label,
4848
"description": description,
49-
"url": BASE_IRI + qid,
49+
"url": f"{ENTITY_IRI}{qid}",
5050
"datePublished": publication_date,
5151
}
52+
5253
if author_ids:
53-
article["author"] = schema_refs_from_ids(author_ids)
54+
profile["author"] = schema_refs_from_ids(author_ids)
5455
if container_ids:
55-
article["isPartOf"] = schema_refs_from_ids(container_ids)
56+
profile["isPartOf"] = schema_refs_from_ids(container_ids)
5657
if publisher_ids:
57-
article["publisher"] = schema_refs_from_ids(publisher_ids)
58+
profile["publisher"] = schema_refs_from_ids(publisher_ids)
5859
if subject_ids:
59-
article["about"] = schema_refs_from_ids(subject_ids)
60+
profile["about"] = schema_refs_from_ids(subject_ids)
6061
if language_ids:
61-
article["inLanguage"] = [BASE_IRI + lang for lang in language_ids]
62+
profile["inLanguage"] = [f"{ENTITY_IRI}{lang}" for lang in language_ids]
63+
6264
if doi_value:
63-
article["identifier"] = {
65+
profile["identifier"] = {
6466
"@type": "PropertyValue",
6567
"propertyID": "doi",
6668
"value": doi_value,
67-
"url": f"https://doi.org/{doi_value}",
69+
"url": f"https://doi.org/{doi_value}"
6870
}
69-
article["sameAs"] = [f"https://doi.org/{doi_value}"]
71+
profile["sameAs"] = [f"https://doi.org/{doi_value}"]
72+
7073
if page_start:
71-
article["pageStart"] = page_start
74+
profile["pageStart"] = page_start
7275
if page_end:
73-
article["pageEnd"] = page_end
76+
profile["pageEnd"] = page_end
7477
if page_range:
75-
article["pagination"] = page_range
78+
profile["pagination"] = page_range
79+
7680
if license_ids:
77-
article["license"] = schema_refs_from_ids(license_ids)
81+
profile["license"] = schema_refs_from_ids(license_ids)
7882
if comment:
79-
article["comment"] = comment
83+
profile["comment"] = comment
8084
if keyword_ids:
81-
article["keyword"] = schema_refs_from_ids(keyword_ids)
85+
profile["keyword"] = schema_refs_from_ids(keyword_ids)
8286
if citation_ids:
83-
article["citation"] = schema_refs_from_ids(citation_ids)
84-
return article
87+
profile["citation"] = schema_refs_from_ids(citation_ids)
88+
89+
return profile

0 commit comments

Comments
 (0)