diff --git a/.github/workflows/on_pr_to_main.yaml b/.github/workflows/on_pr_to_main.yaml
index f41485b4..b8dec758 100644
--- a/.github/workflows/on_pr_to_main.yaml
+++ b/.github/workflows/on_pr_to_main.yaml
@@ -63,6 +63,6 @@ jobs:
cd ../catprez && poetry run pytest
cd ../profiles && poetry run pytest
cd ../services && poetry run pytest
- cd ../curies && poetry run pytest
+ cd ../identifier && poetry run pytest
cd ../object && poetry run pytest
cd ../caching && poetry run pytest
diff --git a/.github/workflows/on_push_to_feature.yaml b/.github/workflows/on_push_to_feature.yaml
index c37b07f7..1064d0c5 100644
--- a/.github/workflows/on_push_to_feature.yaml
+++ b/.github/workflows/on_push_to_feature.yaml
@@ -61,4 +61,5 @@ jobs:
cd ../catprez && poetry run pytest
cd ../profiles && poetry run pytest
cd ../services && poetry run pytest
+ cd ../identifier && poetry run pytest
# cd ../local_sparql_store && poetry run pytest
diff --git a/README.md b/README.md
index 075a9a78..d080c94d 100644
--- a/README.md
+++ b/README.md
@@ -36,6 +36,14 @@ It expects "high quality" data to work well: Prez itself won't patch up bad or m
Prez accesses data stored in an RDF database - a 'triplestore' - and uses the SPARQL Protocol to do so. Any SPARQL Protocol-compliant DB may be used.
+## Redirect Service
+
+As a Linked Data server, Prez provides a redirect service at `/identifier/redirect` that accepts a query parameter `iri`, looks up the `iri` in the database for a `foaf:homepage` predicate with a value, and if it exists, return a redirect response to the value.
+
+This functionality is useful for institutions who issue their own persistent identifiers under a domain name that they control. The mapping from the persistent identifier to the target web resource is stored in the backend SPARQL store.
+
+This is an alternative solution to persistent identifier services such as the [w3id.org](https://w3id.org/). In some cases, it can be used together with such persistent identifier services to avoid the need to provide the redirect mapping in webserver config (NGINX, Apache HTTP, etc.) and instead, define the config as RDF data.
+
## Development
This section is for developing Prez locally. See the [Running](#running) options below for running Prez in production.
@@ -84,20 +92,20 @@ via python-dotenv, or directly in the environment in which Prez is run. The envi
instantiate a Pydantic `Settings` object which is used throughout Prez to configure its behaviour. To see how prez
interprets/uses these environment variables see the `prez/config.py` file.
-| Environment Variable | Description |
-|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| SPARQL_ENDPOINT | Read-only SPARQL endpoint for SpacePrez |
-| SPARQL_USERNAME | A username for Basic Auth against the SPARQL endpoint, if required by the SPARQL endpoint. |
-| SPARQL_PASSWORD | A password for Basic Auth against the SPARQL endpoint, if required by the SPARQL endpoint. |
-| PROTOCOL | The protocol used to deliver Prez. Usually 'http'. |
-| HOST | The host on which to server prez, typically 'localhost'. |
-| PORT | The port Prez is made accessible on. Default is 8000, could be 80 or anything else that your system has permission to use |
-| SYSTEM_URI | Documentation property. An IRI for the Prez system as a whole. This value appears in the landing page RDF delivered by Prez ('/') |
-| LOG_LEVEL | One of CRITICAL, ERROR, WARNING, INFO, DEBUG. Defaults to INFO. |
-| LOG_OUTPUT | "file", "stdout", or "both" ("file" and "stdout"). Defaults to stdout. |
-| PREZ_TITLE | The title to use for Prez instance |
-| PREZ_DESC | A description to use for the Prez instance |
-| DISABLE_PREFIX_GENERATION | Default value is `false`. Very large datasets may want to disable this setting and provide a predefined set of prefixes for namespaces as described in [Link Generation](README-Dev.md#link-generation). |
+| Environment Variable | Description |
+| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| SPARQL_ENDPOINT | Read-only SPARQL endpoint for SpacePrez |
+| SPARQL_USERNAME | A username for Basic Auth against the SPARQL endpoint, if required by the SPARQL endpoint. |
+| SPARQL_PASSWORD | A password for Basic Auth against the SPARQL endpoint, if required by the SPARQL endpoint. |
+| PROTOCOL | The protocol used to deliver Prez. Usually 'http'. |
+| HOST | The host on which to server prez, typically 'localhost'. |
+| PORT | The port Prez is made accessible on. Default is 8000, could be 80 or anything else that your system has permission to use |
+| SYSTEM_URI | Documentation property. An IRI for the Prez system as a whole. This value appears in the landing page RDF delivered by Prez ('/') |
+| LOG_LEVEL | One of CRITICAL, ERROR, WARNING, INFO, DEBUG. Defaults to INFO. |
+| LOG_OUTPUT | "file", "stdout", or "both" ("file" and "stdout"). Defaults to stdout. |
+| PREZ_TITLE | The title to use for Prez instance |
+| PREZ_DESC | A description to use for the Prez instance |
+| DISABLE_PREFIX_GENERATION | Default value is `false`. Very large datasets may want to disable this setting and provide a predefined set of prefixes for namespaces as described in [Link Generation](README-Dev.md#link-generation). |
### Running in a Container
diff --git a/prez/app.py b/prez/app.py
index 530f669e..f9f0324c 100644
--- a/prez/app.py
+++ b/prez/app.py
@@ -25,7 +25,7 @@
from prez.routers.spaceprez import router as spaceprez_router
from prez.routers.sparql import router as sparql_router
from prez.routers.vocprez import router as vocprez_router
-from prez.routers.curie import router as curie_router
+from prez.routers.identifier import router as identifier_router
from prez.services.app_service import healthcheck_sparql_endpoints, count_objects
from prez.services.app_service import populate_api_info, add_prefixes_to_prefix_graph
from prez.services.exception_catchers import (
@@ -61,7 +61,7 @@
app.include_router(catprez_router)
app.include_router(vocprez_router)
app.include_router(spaceprez_router)
-app.include_router(curie_router)
+app.include_router(identifier_router)
@app.middleware("http")
diff --git a/prez/queries/identifier.py b/prez/queries/identifier.py
new file mode 100644
index 00000000..149170a3
--- /dev/null
+++ b/prez/queries/identifier.py
@@ -0,0 +1,18 @@
+from textwrap import dedent
+
+from jinja2 import Template
+
+
+def get_foaf_homepage_query(iri: str) -> str:
+ query = Template(
+ """
+ PREFIX foaf:
+
+ SELECT DISTINCT ?url
+ WHERE {
+ <{{ iri }}> foaf:homepage ?url .
+ }
+ """
+ ).render(iri=iri)
+
+ return dedent(query)
diff --git a/prez/queries/vocprez.py b/prez/queries/vocprez.py
index 7378fac7..a1412b23 100644
--- a/prez/queries/vocprez.py
+++ b/prez/queries/vocprez.py
@@ -63,11 +63,15 @@ def get_concept_scheme_top_concepts_query(iri: str, page: int, per_page: int) ->
?concept prez:childrenCount ?narrowerChildrenCount .
?iri prez:childrenCount ?childrenCount .
?iri skos:hasTopConcept ?concept .
+ ?iri rdf:type ?type .
+ ?concept rdf:type ?conceptType .
}
WHERE {
BIND(<{{ iri }}> as ?iri)
?iri skos:hasTopConcept ?concept .
?concept skos:prefLabel ?label .
+ ?iri rdf:type ?type .
+ ?concept rdf:type ?conceptType .
{
SELECT (COUNT(?childConcept) AS ?childrenCount)
@@ -113,11 +117,15 @@ def get_concept_narrowers_query(iri: str, page: int, per_page: int) -> str:
?concept prez:childrenCount ?narrowerChildrenCount .
?iri prez:childrenCount ?childrenCount .
?iri skos:narrower ?concept .
+ ?iri rdf:type ?type .
+ ?concept rdf:type ?conceptType .
}
WHERE {
BIND(<{{ iri }}> as ?iri)
?concept skos:broader ?iri .
?concept skos:prefLabel ?label .
+ ?iri rdf:type ?type .
+ ?concept rdf:type ?conceptType .
{
SELECT (COUNT(?childConcept) AS ?childrenCount)
diff --git a/prez/reference_data/profiles/vocprez_default_profiles.ttl b/prez/reference_data/profiles/vocprez_default_profiles.ttl
index e7adf7fa..505453ef 100644
--- a/prez/reference_data/profiles/vocprez_default_profiles.ttl
+++ b/prez/reference_data/profiles/vocprez_default_profiles.ttl
@@ -69,7 +69,7 @@ prez:VocPrezProfile
dcterms:identifier "vocpub"^^xsd:token ;
dcterms:title "VocPub" ;
altr-ext:hasLabelPredicate skos:prefLabel ;
- altr-ext:otherAnnotationProps schema:color ;
+ altr-ext:otherAnnotationProps schema:color, reg:status ;
altr-ext:constrainsClass
skos:ConceptScheme ,
skos:Concept ,
diff --git a/prez/renderers/renderer.py b/prez/renderers/renderer.py
index 78ee6d81..8fa48b80 100644
--- a/prez/renderers/renderer.py
+++ b/prez/renderers/renderer.py
@@ -72,6 +72,24 @@ async def return_rdf(graph, mediatype, profile_headers):
return StreamingResponse(content=obj, media_type=mediatype, headers=profile_headers)
+async def get_annotations_graph(profile, graph, cache):
+ profile_annotation_props = get_annotation_predicates(profile)
+ queries_for_uncached, annotations_graph = await get_annotation_properties(
+ graph, **profile_annotation_props
+ )
+
+ if queries_for_uncached is None:
+ anots_from_triplestore = Graph()
+ else:
+ anots_from_triplestore = await queries_to_graph([queries_for_uncached])
+
+ if len(anots_from_triplestore) > 1:
+ annotations_graph += anots_from_triplestore
+ cache += anots_from_triplestore
+
+ return annotations_graph
+
+
async def return_annotated_rdf(
graph: Graph,
profile_headers,
@@ -84,27 +102,19 @@ async def return_annotated_rdf(
non_anot_mediatype = mediatype.replace("anot+", "")
cache = tbox_cache
- profile_annotation_props = get_annotation_predicates(profile)
- queries_for_uncached, annotations_graph = await get_annotation_properties(
- graph, **profile_annotation_props
- )
- if queries_for_uncached is None:
- anots_from_triplestore = Graph()
- else:
- anots_from_triplestore = await queries_to_graph([queries_for_uncached])
+ previous_triples_count = len(graph)
- if len(anots_from_triplestore) > 1:
- annotations_graph += anots_from_triplestore
- cache += anots_from_triplestore
+ # Expand the graph with annotations specified in the profile until no new statements are added.
+ while True:
+ graph += await get_annotations_graph(profile, graph, cache)
+ if len(graph) == previous_triples_count:
+ break
+ previous_triples_count = len(graph)
generate_prez_links(graph, predicates_for_link_addition)
- obj = io.BytesIO(
- (graph + annotations_graph).serialize(
- format=non_anot_mediatype, encoding="utf-8"
- )
- )
+ obj = io.BytesIO(graph.serialize(format=non_anot_mediatype, encoding="utf-8"))
return StreamingResponse(
content=obj, media_type=non_anot_mediatype, headers=profile_headers
)
diff --git a/prez/routers/curie.py b/prez/routers/identifier.py
similarity index 60%
rename from prez/routers/curie.py
rename to prez/routers/identifier.py
index 8cff8c83..3e05f47e 100644
--- a/prez/routers/curie.py
+++ b/prez/routers/identifier.py
@@ -1,13 +1,43 @@
-from fastapi import APIRouter, HTTPException, status
-from fastapi.responses import PlainTextResponse
+from fastapi import APIRouter, HTTPException, status, Request
+from fastapi.responses import PlainTextResponse, RedirectResponse
from rdflib import URIRef
from rdflib.term import _is_valid_uri
from prez.services.curie_functions import get_uri_for_curie_id, get_curie_id_for_uri
+from prez.queries.identifier import get_foaf_homepage_query
+from prez.sparql.methods import sparql_query_non_async
router = APIRouter(tags=["Identifier Resolution"])
+@router.get(
+ "/identifier/redirect",
+ summary="Get a redirect response to the resource landing page",
+ response_class=RedirectResponse,
+ responses={
+ status.HTTP_404_NOT_FOUND: {"content": {"application/json": {}}},
+ },
+)
+def get_identifier_redirect_route(iri: str, request: Request):
+ """
+ The `iri` query parameter is used to return a redirect response with the value from the `foaf:homepage` lookup.
+ If no value is found, a 404 HTTP response is returned.
+ """
+ query = get_foaf_homepage_query(iri)
+ _, result = sparql_query_non_async(query)
+ url = None
+ for row in result:
+ url = row["url"]["value"]
+
+ if url is None:
+ raise HTTPException(
+ status.HTTP_404_NOT_FOUND, f"No homepage found for IRI {iri}."
+ )
+
+ # Note: currently does not forward query parameters but we may want to implement this in the future.
+ return RedirectResponse(url, headers=request.headers)
+
+
@router.get(
"/identifier/curie/{iri:path}",
summary="Get the IRI's CURIE identifier",
diff --git a/prez/routers/object.py b/prez/routers/object.py
index 8f9a941d..90176124 100644
--- a/prez/routers/object.py
+++ b/prez/routers/object.py
@@ -2,7 +2,7 @@
from starlette.responses import PlainTextResponse
from prez.models import SpatialItem, VocabItem, CatalogItem
-from prez.routers.curie import get_iri_route
+from prez.routers.identifier import get_iri_route
from prez.sparql.methods import sparql_query_non_async
from prez.queries.object import object_inbound_query, object_outbound_query
diff --git a/prez/routers/vocprez.py b/prez/routers/vocprez.py
index 8b50d71c..a679cee2 100644
--- a/prez/routers/vocprez.py
+++ b/prez/routers/vocprez.py
@@ -29,7 +29,7 @@
get_concept_narrowers_query,
)
from prez.response import StreamingTurtleAnnotatedResponse
-from prez.routers.curie import get_iri_route
+from prez.routers.identifier import get_iri_route
router = APIRouter(tags=["VocPrez"])
diff --git a/tests/data/spaceprez/input/redirect-foaf-homepage.ttl b/tests/data/spaceprez/input/redirect-foaf-homepage.ttl
new file mode 100644
index 00000000..1274566e
--- /dev/null
+++ b/tests/data/spaceprez/input/redirect-foaf-homepage.ttl
@@ -0,0 +1,3 @@
+PREFIX foaf:
+
+ foaf:homepage .
diff --git a/tests/data/vocprez/expected_responses/beddingsurfacestructure_top_concepts.ttl b/tests/data/vocprez/expected_responses/beddingsurfacestructure_top_concepts.ttl
new file mode 100644
index 00000000..8a27098b
--- /dev/null
+++ b/tests/data/vocprez/expected_responses/beddingsurfacestructure_top_concepts.ttl
@@ -0,0 +1,255 @@
+PREFIX dcterms:
+PREFIX ns1:
+PREFIX ns2:
+PREFIX rdfs:
+PREFIX schema:
+PREFIX skos:
+PREFIX xsd:
+
+
+ a skos:ConceptScheme ;
+ ns2:status ;
+ skos:hasTopConcept
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ;
+ skos:prefLabel "BeddingSurfaceStructure"@en ;
+ ns1:childrenCount 21 ;
+.
+
+dcterms:description
+ rdfs:label "Description"@en ;
+ dcterms:description "Description may include but is not limited to: an abstract, a table of contents, a graphical representation, or a free-text account of the resource."@en ;
+.
+
+dcterms:identifier
+ rdfs:label "Identifier"@en ;
+ dcterms:description "Recommended practice is to identify the resource by means of a string conforming to an identification system. Examples include International Standard Book Number (ISBN), Digital Object Identifier (DOI), and Uniform Resource Name (URN). Persistent identifiers should be provided as HTTP URIs."@en ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Shrinkage (Desiccation) Cracks"@en ;
+ dcterms:identifier "bddngsrfcstrctr:CRACKDES"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Shrinkage (Desiccation) Cracks"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:CRACKDES" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Synaeresis Cracks"@en ;
+ dcterms:identifier "bddngsrfcstrctr:CRACKSYN"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Synaeresis Cracks"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:CRACKSYN" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Parting Lineation (Primary Current Lineation)"@en ;
+ dcterms:identifier "bddngsrfcstrctr:PART"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Parting Lineation (Primary Current Lineation)"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:PART" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Rainspots"@en ;
+ dcterms:identifier "bddngsrfcstrctr:RAIN"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Rainspots"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:RAIN" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Ripples"@en ;
+ dcterms:identifier "bddngsrfcstrctr:RIP"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Ripples"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:RIP" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Current Ripples"@en ;
+ dcterms:identifier "bddngsrfcstrctr:RIPCUR"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Current Ripples"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:RIPCUR" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Linguoid Current Ripples"@en ;
+ dcterms:identifier "bddngsrfcstrctr:RIPCURLIN"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Linguoid Current Ripples"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:RIPCURLIN" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Sinuous-Crested Current Rippled"@en ;
+ dcterms:identifier "bddngsrfcstrctr:RIPCURSIN"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Sinuous-Crested Current Rippled"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:RIPCURSIN" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Straight-Crested Current Ripples"@en ;
+ dcterms:identifier "bddngsrfcstrctr:RIPCURSTR"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Straight-Crested Current Ripples"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:RIPCURSTR" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Wave-Formed Ripples"@en ;
+ dcterms:identifier "bddngsrfcstrctr:RIPWAV"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Wave-Formed Ripples"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:RIPWAV" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Interference Wave-Formed Ripples"@en ;
+ dcterms:identifier "bddngsrfcstrctr:RIPWAVINT"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Interference Wave-Formed Ripples"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:RIPWAVINT" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Modified Wave-Formed Ripples"@en ;
+ dcterms:identifier "bddngsrfcstrctr:RIPWAVMOD"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Modified Wave-Formed Ripples"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:RIPWAVMOD" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Trace Fossils"@en ;
+ dcterms:identifier "bddngsrfcstrctr:TF"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Trace Fossils"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:TF" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Crawling / Walking Tracks and Trails"@en ;
+ dcterms:identifier "bddngsrfcstrctr:TFCR"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Crawling / Walking Tracks and Trails"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:TFCR" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Foot Prints"@en ;
+ dcterms:identifier "bddngsrfcstrctr:TFCRFOOT"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Foot Prints"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:TFCRFOOT" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Grazing Traces"@en ;
+ dcterms:identifier "bddngsrfcstrctr:TFGRZ"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Grazing Traces"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:TFGRZ" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Coiled Grazing Traces"@en ;
+ dcterms:identifier "bddngsrfcstrctr:TFGRZCOIL"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Coiled Grazing Traces"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:TFGRZCOIL" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Meandering Grazing Traces"@en ;
+ dcterms:identifier "bddngsrfcstrctr:TFGRZMEAND"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Meandering Grazing Traces"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:TFGRZMEAND" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Radial Grazing Traces"@en ;
+ dcterms:identifier "bddngsrfcstrctr:TFGRZRAD"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Radial Grazing Traces"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:TFGRZRAD" ;
+.
+
+
+ a skos:Concept ;
+ rdfs:label "Resting Traces"@en ;
+ dcterms:identifier "bddngsrfcstrctr:TFREST"^^ns1:identifier ;
+ ns2:status ;
+ skos:prefLabel "Resting Traces"@en ;
+ ns1:childrenCount 0 ;
+ ns1:link "/v/vocab/ref:BeddingSurfaceStructure/bddngsrfcstrctr:TFREST" ;
+.
+
+
+ skos:prefLabel "experimental"@en ;
+ schema:color "#eae72c" ;
+.
+
+
+ skos:prefLabel "valid"@en ;
+ schema:color "#36a80d" ;
+.
\ No newline at end of file
diff --git a/tests/data/vocprez/expected_responses/collection_listing_anot.ttl b/tests/data/vocprez/expected_responses/collection_listing_anot.ttl
index 617a244e..3f2a822e 100644
--- a/tests/data/vocprez/expected_responses/collection_listing_anot.ttl
+++ b/tests/data/vocprez/expected_responses/collection_listing_anot.ttl
@@ -1,19 +1,35 @@
-@prefix dcterms: .
-@prefix ns1: .
-@prefix skos: .
-@prefix xsd: .
+PREFIX dcterms:
+PREFIX ns1:
+PREFIX rdfs:
+PREFIX skos:
+PREFIX xsd:
- a skos:Collection ;
+
+ a skos:Collection ;
dcterms:provenance "Compiled by the Geological Survey of Queensland" ;
skos:definition "Borehole purposes applicable to regulatory notification forms."@en ;
skos:prefLabel "PGGD selection"@en ;
- ns1:link "/v/collection/brhl-prps:pggd" .
+ ns1:link "/v/collection/brhl-prps:pggd" ;
+.
- a skos:Collection ;
+dcterms:description
+ rdfs:label "Description"@en ;
+ dcterms:description "Description may include but is not limited to: an abstract, a table of contents, a graphical representation, or a free-text account of the resource."@en ;
+.
+
+dcterms:provenance
+ rdfs:label "Provenance"@en ;
+ dcterms:description "The statement may include a description of any changes successive custodians made to the resource."@en ;
+.
+
+
+ a skos:Collection ;
dcterms:provenance "this vocabulary" ;
skos:definition "All Concepts in this vocabulary" ;
skos:prefLabel "Contact Type - All Concepts"@en ;
- ns1:link "/v/collection/cgi:contacttype" .
-
-skos:Collection ns1:count 2 .
+ ns1:link "/v/collection/cgi:contacttype" ;
+.
+skos:Collection
+ ns1:count 2 ;
+.
\ No newline at end of file
diff --git a/tests/data/vocprez/expected_responses/collection_listing_item.ttl b/tests/data/vocprez/expected_responses/collection_listing_item.ttl
index 921b20cc..47585167 100644
--- a/tests/data/vocprez/expected_responses/collection_listing_item.ttl
+++ b/tests/data/vocprez/expected_responses/collection_listing_item.ttl
@@ -1,197 +1,318 @@
-@prefix dcterms: .
-@prefix ns1: .
-@prefix rdfs: .
-@prefix skos: .
-@prefix xsd: .
-
-dcterms:identifier rdfs:label "Identifier"@en ;
- dcterms:description "Recommended practice is to identify the resource by means of a string conforming to an identification system. Examples include International Standard Book Number (ISBN), Digital Object Identifier (DOI), and Uniform Resource Name (URN). Persistent identifiers should be provided as HTTP URIs."@en .
-
-dcterms:provenance rdfs:label "Provenance"@en ;
- dcterms:description "The statement may include a description of any changes successive custodians made to the resource."@en .
-
- a skos:Collection ;
+PREFIX dcterms:
+PREFIX ns1:
+PREFIX ns2:
+PREFIX rdfs:
+PREFIX skos:
+PREFIX xsd:
+
+dcterms:description
+ rdfs:label "Description"@en ;
+ dcterms:description "Description may include but is not limited to: an abstract, a table of contents, a graphical representation, or a free-text account of the resource."@en ;
+.
+
+dcterms:identifier
+ rdfs:label "Identifier"@en ;
+ dcterms:description "Recommended practice is to identify the resource by means of a string conforming to an identification system. Examples include International Standard Book Number (ISBN), Digital Object Identifier (DOI), and Uniform Resource Name (URN). Persistent identifiers should be provided as HTTP URIs."@en ;
+.
+
+dcterms:provenance
+ rdfs:label "Provenance"@en ;
+ dcterms:description "The statement may include a description of any changes successive custodians made to the resource."@en ;
+.
+
+
+ a skos:Collection ;
dcterms:identifier "contacttype"^^xsd:token ;
dcterms:provenance "this vocabulary" ;
skos:definition "All Concepts in this vocabulary" ;
- skos:member ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
+ skos:member
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
;
- skos:prefLabel "Contact Type - All Concepts"@en .
+ skos:prefLabel "Contact Type - All Concepts"@en ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "alteration facies contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:alteration_facies_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:alteration_facies_contact" ;
+.
- dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+
+ dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+ ns2:status ;
skos:prefLabel "angular unconformable contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:angular_unconformable_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:angular_unconformable_contact" ;
+.
- dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+
+ dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+ ns2:status ;
skos:prefLabel "buttress unconformity"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:buttress_unconformity" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:buttress_unconformity" ;
+.
- dcterms:provenance "FGDC"@en ;
+
+ dcterms:provenance "FGDC"@en ;
+ ns2:status ;
skos:prefLabel "chronostratigraphic-zone contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:chronostratigraphic_zone_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:chronostratigraphic_zone_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "conductivity contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:conductivity_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:conductivity_contact" ;
+.
- dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+
+ dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+ ns2:status ;
skos:prefLabel "conformable contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:conformable_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:conformable_contact" ;
+.
- dcterms:provenance "adapted from Jackson, 1997, page 137, NADM C1 2004"@en ;
+
+ dcterms:provenance "adapted from Jackson, 1997, page 137, NADM C1 2004"@en ;
+ ns2:status ;
skos:prefLabel "contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "deformation zone contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:deformation_zone_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:deformation_zone_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "density contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:density_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:density_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "depositional contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:depositional_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:depositional_contact" ;
+.
- dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+
+ dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+ ns2:status ;
skos:prefLabel "disconformable contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:disconformable_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:disconformable_contact" ;
+.
- dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+
+ dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+ ns2:status ;
skos:prefLabel "faulted contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:faulted_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:faulted_contact" ;
+.
- dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+
+ dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+ ns2:status ;
skos:prefLabel "geologic province contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:geologic_province_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:geologic_province_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "geophysical contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:geophysical_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:geophysical_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "glacial stationary line"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:glacial_stationary_line" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:glacial_stationary_line" ;
+.
- dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+
+ dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+ ns2:status ;
skos:prefLabel "igneous intrusive contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:igneous_intrusive_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:igneous_intrusive_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "igneous phase contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:igneous_phase_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:igneous_phase_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "impact structure boundary"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:impact_structure_boundary" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:impact_structure_boundary" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "lithogenetic contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:lithogenetic_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:lithogenetic_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "magnetic contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:magnetic_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:magnetic_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "magnetic polarity contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:magnetic_polarity_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:magnetic_polarity_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "magnetic susceptiblity contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:magnetic_susceptiblity_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:magnetic_susceptiblity_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "magnetization contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:magnetization_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:magnetization_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "metamorphic contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:metamorphic_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:metamorphic_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "metamorphic facies contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:metamorphic_facies_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:metamorphic_facies_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "metasomatic facies contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:metasomatic_facies_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:metasomatic_facies_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "mineralisation assemblage contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:mineralisation_assemblage_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:mineralisation_assemblage_contact" ;
+.
- dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+
+ dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+ ns2:status ;
skos:prefLabel "nonconformable contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:nonconformable_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:nonconformable_contact" ;
+.
- dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+
+ dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+ ns2:status ;
skos:prefLabel "paraconformable contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:paraconformable_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:paraconformable_contact" ;
+.
- dcterms:provenance "this vocabulary"@en ;
+
+ dcterms:provenance "this vocabulary"@en ;
+ ns2:status ;
skos:prefLabel "radiometric contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:radiometric_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:radiometric_contact" ;
+.
- dcterms:provenance "base on Nichols, Gary, 1999, Sedimentology and stratigraphy, Blackwell, p. 62-63."@en ;
+
+ dcterms:provenance "base on Nichols, Gary, 1999, Sedimentology and stratigraphy, Blackwell, p. 62-63."@en ;
+ ns2:status ;
skos:prefLabel "sedimentary facies contact"@en ;
- ns1:link "/v/collection/cgi:contacttype/cntcttyp:sedimentary_facies_contact" .
+ ns1:link "/v/collection/cgi:contacttype/cntcttyp:sedimentary_facies_contact" ;
+.
- dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+
+ dcterms:provenance "Neuendorf, K.K.E, Mehl, J.P. & Jackson, J.A. (eds), 2005. Glossary of geology, 5th Edition. American Geological Institute, Alexandria, 779 p."@en ;
+ ns2:status