URI resolving, RDF formats and content-negotiation [module proposal]

Intro

This idea is posted here to get feedback of the Omeka S community. Is this a user story you can relate to? Is the described functionality not already present in an existing Omeka S module? Is the description/requirements clear enough (in order for a developer to work on a module)?

User story

I’d like to request the data of an Omeka S Item in other RDF formats, by using content-negotiation (or: I want my Linked Data URIs to resolve) .

Concepts

The most common RDF formats are:

  • Turtle (Terse RDF Triple Language): A more human-readable format using a compact syntax, suitable for writing and reading RDF data.
  • N-Triples: A plain-text format representing one RDF triple per line, making it easy to process and generate.
  • N-Quads: An extension of N-Triples that includes an additional graph name component, useful for representing named graphs.
  • RDF/XML: A widely used and original RDF serialization format, based on XML syntax.
  • JSON-LD: A JSON-based format that allows RDF data to be represented in a way that is both human-readable and machine-processable. This is the format used by Omeka S to output the linked data.

HTTP content negotiation is a mechanism used by web servers and clients to determine the most appropriate representation of a resource to send in response to an HTTP request. When a client makes a request to a web server, it can include certain headers, such as “Accept” and “Accept-Language,” indicating the preferred content types and languages it can handle. The server examines these headers along with other factors, like the available representations of the requested resource and the server’s configuration, to determine the best response to send back to the client. This way, content negotiation allows servers to provide content tailored to the client’s capabilities, improving the overall user experience and enabling more efficient use of network resources. Common content types negotiated include HTML, JSON, XML, and different media types like images or videos.

Examples (proof of concept)

An alley in Gouda, in (standard Omeka S) JSON-LD format: https://www.goudatijdmachine.nl/data/api/items/37476

When I want the Turtle representation of this URI, I specify this in the Accept header:
curl -L -H "Accept: text/turtle" https://www.goudatijdmachine.nl/data/api/items/37476 (*)

The response:

@prefix gtm: <https://www.goudatijdmachine.nl/def#> .
@prefix ns0: <http://omeka.org/s/vocabs/module/mapping#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix dc: <http://purl.org/dc/terms/> .
@prefix hg: <http://rdf.histograph.io/> .
@prefix sem: <http://semanticweb.cs.vu.nl/2009/11/sem/> .
@prefix geo: <http://www.opengis.net/ont/geosparql#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix schema: <https://schema.org/> .

<https://www.goudatijdmachine.nl/data/api/items/37476>
  a o:Item, gtm:Straat ;
  ns0:marker <https://www.goudatijdmachine.nl/data/api/mapping_markers/59638> ;
  o:created "2022-04-02T13:36:49+00:00"^^xsd:dateTime ;
  o:id 37476 ;
  o:is_public true ;
  o:item_set <https://www.goudatijdmachine.nl/data/api/item_sets/2> ;
  o:modified "2023-04-19T12:14:38+00:00"^^xsd:dateTime ;
  o:owner <https://www.goudatijdmachine.nl/data/api/users/2> ;
  o:resource_class <https://www.goudatijdmachine.nl/data/api/resource_classes/909> ;
  o:resource_template <https://www.goudatijdmachine.nl/data/api/resource_templates/2> ;
  o:site <https://www.goudatijdmachine.nl/data/api/sites/2> ;
  o:title "Arie Kerssensteegje"^^xsd:string ;
  dc:identifier "ark:/60537/b3xVzO"^^xsd:string ;
  hg:liesIn <https://www.goudatijdmachine.nl/data/api/items/37823> ;
  sem:hasEarliestBeginTimeStamp "1647-01-01"^^xsd:date ;
  geo:asWKT "LINESTRING (4.7084154 52.01158, 4.7080402 52.0113713, 4.7077826 52.112286, 4.7072074 52.01092)"^^geo:wktLiteral ;
  owl:sameAs <http://www.wikidata.org/entity/Q18940281>, <http://bag.basisregistraties.overheid.nl/bag/id/openbare-ruimte/0513300000000339> ;
  skos:prefLabel "Arie Kerssensteegje"^^xsd:string ;
  schema:identifier "straat/arie-kerssensteegje"^^xsd:string ;
  schema:mentions "Bu0026W besluit, nummer 3919 (2-03-1993)"^^xsd:string .

<https://www.goudatijdmachine.nl/data/api/mapping_markers/59638> o:id 59638 .
<https://www.goudatijdmachine.nl/data/api/item_sets/2> o:id 2 .
<https://www.goudatijdmachine.nl/data/api/users/2> o:id 2 .
<https://www.goudatijdmachine.nl/data/api/resource_classes/909> o:id 909 .
<https://www.goudatijdmachine.nl/data/api/resource_templates/2> o:id 2 .
<https://www.goudatijdmachine.nl/data/api/sites/2> o:id 2 .
<http://www.wikidata.org/entity/Q18940281> o:label "Wikidata Q18940281"^^xsd:string .
<http://bag.basisregistraties.overheid.nl/bag/id/openbare-ruimte/0513300000000339> o:label "BAG id 0513300000000339"^^xsd:string .

Or, if I want the Item in N-Triples, the request curl -L -H "Accept: application/n-triples" https://www.goudatijdmachine.nl/data/api/items/37476 gives as response:

<https://www.goudatijdmachine.nl/data/api/items/37476> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://omeka.org/s/vocabs/o#Item> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.goudatijdmachine.nl/def#Straat> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://omeka.org/s/vocabs/module/mapping#marker> <https://www.goudatijdmachine.nl/data/api/mapping_markers/59638> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://omeka.org/s/vocabs/o#created> "2022-04-02T13:36:49+00:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://omeka.org/s/vocabs/o#id> "37476"^^<http://www.w3.org/2001/XMLSchema#integer> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://omeka.org/s/vocabs/o#is_public> "true"^^<http://www.w3.org/2001/XMLSchema#boolean> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://omeka.org/s/vocabs/o#item_set> <https://www.goudatijdmachine.nl/data/api/item_sets/2> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://omeka.org/s/vocabs/o#modified> "2023-04-19T12:14:38+00:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://omeka.org/s/vocabs/o#owner> <https://www.goudatijdmachine.nl/data/api/users/2> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://omeka.org/s/vocabs/o#resource_class> <https://www.goudatijdmachine.nl/data/api/resource_classes/909> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://omeka.org/s/vocabs/o#resource_template> <https://www.goudatijdmachine.nl/data/api/resource_templates/2> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://omeka.org/s/vocabs/o#site> <https://www.goudatijdmachine.nl/data/api/sites/2> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://omeka.org/s/vocabs/o#title> "Arie Kerssensteegje"^^<http://www.w3.org/2001/XMLSchema#string> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://purl.org/dc/terms/identifier> "ark:/60537/b3xVzO"^^<http://www.w3.org/2001/XMLSchema#string> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://rdf.histograph.io/liesIn> <https://www.goudatijdmachine.nl/data/api/items/37823> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://semanticweb.cs.vu.nl/2009/11/sem/hasEarliestBeginTimeStamp> "1647-01-01"^^<http://www.w3.org/2001/XMLSchema#date> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://www.opengis.net/ont/geosparql#asWKT> "LINESTRING (4.7084154 52.01158, 4.7080402 52.0113713, 4.7077826 52.0112286, 4.7072074 52.01092)"^^<http://www.opengis.net/ont/geosparql#wktLiteral> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://www.w3.org/2002/07/owl#sameAs> <http://www.wikidata.org/entity/Q18940281> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://www.w3.org/2002/07/owl#sameAs> <http://bag.basisregistraties.overheid.nl/bag/id/openbare-ruimte/0513300000000339> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <http://www.w3.org/2004/02/skos/core#prefLabel> "Arie Kerssensteegje"^^<http://www.w3.org/2001/XMLSchema#string> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <https://schema.org/identifier> "straat/arie-kerssensteegje"^^<http://www.w3.org/2001/XMLSchema#string> .
<https://www.goudatijdmachine.nl/data/api/items/37476> <https://schema.org/mentions> "Bu0026W besluit, nummer 3919 (2-03-1993)"^^<http://www.w3.org/2001/XMLSchema#string> .
<https://www.goudatijdmachine.nl/data/api/mapping_markers/59638> <http://omeka.org/s/vocabs/o#id> "59638"^^<http://www.w3.org/2001/XMLSchema#integer> .
<https://www.goudatijdmachine.nl/data/api/item_sets/2> <http://omeka.org/s/vocabs/o#id> "2"^^<http://www.w3.org/2001/XMLSchema#integer> .
<https://www.goudatijdmachine.nl/data/api/users/2> <http://omeka.org/s/vocabs/o#id> "2"^^<http://www.w3.org/2001/XMLSchema#integer> .
<https://www.goudatijdmachine.nl/data/api/resource_classes/909> <http://omeka.org/s/vocabs/o#id> "909"^^<http://www.w3.org/2001/XMLSchema#integer> .
<https://www.goudatijdmachine.nl/data/api/resource_templates/2> <http://omeka.org/s/vocabs/o#id> "2"^^<http://www.w3.org/2001/XMLSchema#integer> .
<https://www.goudatijdmachine.nl/data/api/sites/2> <http://omeka.org/s/vocabs/o#id> "2"^^<http://www.w3.org/2001/XMLSchema#integer> .
<http://www.wikidata.org/entity/Q18940281> <http://omeka.org/s/vocabs/o#label> "Wikidata Q18940281"^^<http://www.w3.org/2001/XMLSchema#string> .
<http://bag.basisregistraties.overheid.nl/bag/id/openbare-ruimte/0513300000000339> <http://omeka.org/s/vocabs/o#label> "BAG id 0513300000000339"^^<http://www.w3.org/2001/XMLSchema#string> .

*) this should also work with persistent identifiers, so curl -L -H "Accept: text/turtle" https://n2t.net/ark:/60537/b3xVzO returns the same result (it’s the client who follows the redirects -L and to pass on the Accept header -H in each request).

This proof-of-concept gets the JSON-LD of the item and converts this to the requested RDF format via (EasyRdf)[https://www.easyrdf.org/].

Module requirements

  • Able to output data in Turtle, N-Triples, N-Quads, RDF/XML (and JSON-LD)

This is a great suggestion. It happens to be a feature that should be in the next minor release, reflected in these two pull requests:

In addition to JSON-LD, clients can choose RDF-XML, N3, Turtle, and N-Triples, using content negotiation or a format= URL query. Modules can extend this list of available formats using the new api.output.formats and api.output.serialize events.

1 Like