Using Virtuoso as LDP Client and Server
- What is the Linked Data Platform (LDP)?
- Why is the LDP important?
- How to use Virtuoso’s LDP features
- Example 1: How to enable LDP on a folder/collection
- Example 2: Create and verify a simple LDPR
- Example 3: Create an LDPR from an existing text file containing Turtle data
- Example 4: Access Resources in an LDPC (e.g., a DAV folder)
- Example 5: Delete Resources in an LDPC (e.g., a DAV folder)
- Example 6: Creating LDPR via POST requests
- Related
What is the Linked Data Platform (LDP)?
Use of HTTP to Create, Read, Update, and Delete Linked Data Resources (Documents) that are part of a collection (folder). Naturally, this kind of task posses the following questions and associated challenges:
- Document Resource Issues
- What resource content notations and across-the-wire content serialization formats should be used?
- How is collision detection for updates handled with maximum concurrent (i.e. optimistically)?
- How do client handle changes to associated resources, such as content type changes?
- How servers ease the burden of constraints associated with resource creation?
- Container/Folder Resource Issues
- To which address/location (URL) on an HTTP network can I
POST
my resource member or container creation requests? - How do I
GET
(retrieve) a list of existing member resources associated with a container? - How is container ordering of member resources expressed and represented?
- How do I obtain metadata about the resources that are members of a container, and the container resource itself?
- How do I
GET
retrieve resources that are members of a large container, using paging? - How do I deal with metadata querying scoped to member resources and container resources?
- To which address/location (URL) on an HTTP network can I
The Linked Data Platform (LDP) was developed by W3C members to answer many of these questions.
Why is the LDP important?
It formalizes Linked Data deployment and use by standardizing the representation and behavior of, and the generation and processing of HTTP requests regarding, Linked Data Platform Resources (LDPRs) and Linked Data Platform Containers (LDPCs). Using the Linked Data Platform thereby increases availability and accessibility of Linked Data on the Web.
How to use Virtuoso’s LDP features
Virtuoso’s LDP functionality is a built-in, integral part of the product.
Virtuoso operates as an LDP Client, generating HTTP requests and processing HTTP responses that conform to the rules defined for LDPRs and LDPCs, when it is operating against LDP Servers.
Virtuoso also operates as an LDP Server, by processing HTTP requests and generating HTTP responses that conform to the rules defined for LDPRs and LDPCs. The following examples use the command line utility curl
to demonstrate Virtuoso’s LDP Server implementation.
Example 1: How to enable LDP on a folder/collection
The Virtuoso Conductor can be used to enable LDP on a WebDAV folder/collection of resources as follows
One could use the following options to enable LDP on a given folder/collection of resources:
- Log in to the conductor at
http://host:port/conductor
and go toWeb Application Server
→Content Management
:
- Provide a location path for the destination
folder/collection
to be LDP enabled, in our example we will enable thedemo
usersPublic
folder:
- Click on
Action
columnUpdate Properties
icon for thePublic
folder:
- Select the
LDP enable/disable
checkbox option to enable the folder for LDP use:
- Click the
Update
button to save the change.
Note, the LDP
property can also be set from command line using the DB.DBA.DAV_PROP_SET() procedure, with:
SQL> DB.DBA.DAV_PROP_SET ('/DAV/home/demo/Public/', 'LDP', 'ldp:BasicContainer', 1, 'dav','dav');
Done. -- 0 msec.
SQL>
Example 2: Create and verify a simple LDPR
- Write a bit of text (“
This content is not Turtle.
” in this example) to a text file (“test2.txt
”) in DAV:
curl -iX PUT -H "Content-Type: text/plain" -u dav:dav -d 'This content is not Turtle.' "http://localhost:8890/DAV/home/demo/Public/test2.txt"
- The server response should be of the form:
$ curl -iX PUT -H "Content-Type: text/plain" -u dav:dav -d 'This content is not Turtle.' "http://localhost:8890/DAV/home/demo/Public/test2.txt"
HTTP/1.1 201 Created
Server: Virtuoso/07.20.3238 (Linux) x86_64-pc-linux-gnu
Connection: close
Date: Fri, 01 Dec 2023 12:04:26 GMT
Accept-Ranges: bytes
Location: http://localhost:8890/DAV/home/demo/Public/test2.txt
Allow: COPY, DELETE, GET, HEAD, LOCK, MKCOL, MOVE, OPTIONS, PATCH, POST, PROPFIND, PROPPATCH, PUT, TRACE, UNLOCK
Vary: Accept-Encoding, Access-Control-Request-Headers, Origin
MS-Author-Via: DAV,SPARQL
Accept-Patch: application/sparql-update
Accept-Post: text/turtle, text/n3, text/nt, text/html, application/ld+json
Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"
Link: <http://www.w3.org/ns/ldp#NonRDFSource>; rel="type"
Link: <http://localhost:8890/DAV/home/demo/Public/test2.txt,meta>; rel="describedby"
Link: <http://localhost:8890/DAV/home/demo/Public/test2.txt,meta>; rel="meta"; title="Metadata File"
ETag: "0b63097a2be403d0f0d7d9fbcedd42bb"
Content-Type: text/plain
Content-Length: 189
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><HTML><HEAD><TITLE>201 Created</TITLE></HEAD><BODY><H1>Created</H1>Resource /DAV/home/demo/Public/test2.txt has been created.</BODY></HTML>
$
- Confirm that the server took the submission as LDP data with the commands:
- Using content negotiation to get RDF(Turtle):
curl -iHAccept:text/turtle http://localhost:8890/DAV/home/demo/Public/test2.txt
- The server response should be of the form:
$ curl -iHAccept:text/turtle http://localhost:8890/DAV/home/demo/Public/test2.txt
HTTP/1.1 200 OK
Server: Virtuoso/07.20.3238 (Linux) x86_64-pc-linux-gnu
Connection: Keep-Alive
Date: Fri, 01 Dec 2023 12:21:03 GMT
Accept-Ranges: bytes
Allow: COPY, DELETE, GET, HEAD, LOCK, MKCOL, MOVE, OPTIONS, PATCH, POST, PROPFIND, PROPPATCH, PUT, TRACE, UNLOCK
Vary: Accept-Encoding, Access-Control-Request-Headers, Origin
MS-Author-Via: DAV,SPARQL
Accept-Patch: application/sparql-update
Accept-Post: text/turtle, text/n3, text/nt, text/html, application/ld+json
Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"
Link: <http://www.w3.org/ns/ldp#NonRDFSource>; rel="type"
Link: <http://localhost:8890/DAV/home/demo/Public/test2.txt,meta>; rel="describedby"
Link: <?p=1>; rel="first"
Link: <?p=1>; rel="last"
Link: <http://localhost:8890/DAV/home/demo/Public/test2.txt,meta>; rel="meta"; title="Metadata File"
ETag: "0b63097a2be403d0f0d7d9fbcedd42bb"
X-SPARQL-default-graph: http://hfw.openlinksw.com:8890/DAV/home/demo/Public/test2.txt
Content-disposition: filename=sparql_2023-12-01_12-21-03Z.ttl
Content-Type: text/turtle
Content-Length: 257
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix ldp: <http://www.w3.org/ns/ldp#> .
<http://localhost:8890/DAV/home/demo/Public/test2.txt>
rdf:type rdfs:Resource , ldp:Resource .
$
- Without content negotiation ie native to the resource:
$ curl -i http://localhost:8890/DAV/home/demo/Public/test2.txt && echo
- The server response should be of the form:
$ curl -i http://localhost:8890/DAV/home/demo/Public/test2.txt && echo
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Content-Length: 27
This content is not Turtle.
$
Example 3: Create an LDPR from an existing text file containing Turtle data
- Assuming a file named
ldp-books.ttl
with the following Turtle content –
@prefix : <http://example.org/book/> .
@prefix ns: <http://example.org/ns#> .
:book1 <http://purl.org/dc/elements/1.1/title> "LDP Tutorial"
; ns:price 42
; ns:discount 0.2
.
:book2 <http://purl.org/dc/elements/1.1/title> "The Semantic Web"
; ns:price 23
; ns:discount 0.25
.
curl -X PUT --data-binary @./ldp-books.ttl -iH "Content-Type: text/turtle" -u dav:dav "http://localhost:8890/DAV/home/demo/Public/ldp-books.ttl"
- The server response should be of the form:
$ curl -X PUT --data-binary @./ldp-books.ttl -iH "Content-Type: text/turtle" -u dav:dav "http://localhost:8890/DAV/home/demo/Public/ldp-books.ttl"
HTTP/1.1 201 Created
Server: Virtuoso/07.20.3238 (Linux) x86_64-pc-linux-gnu
Connection: close
Date: Fri, 01 Dec 2023 10:15:21 GMT
Accept-Ranges: bytes
Location: http://localhost:8890/DAV/home/demo/Public/ldp-books.ttl
Allow: COPY, DELETE, GET, HEAD, LOCK, MKCOL, MOVE, OPTIONS, PATCH, POST, PROPFIND, PROPPATCH, PUT, TRACE, UNLOCK
Vary: Accept-Encoding, Access-Control-Request-Headers, Origin
MS-Author-Via: DAV,SPARQL
Accept-Patch: application/sparql-update
Accept-Post: text/turtle, text/n3, text/nt, text/html, application/ld+json
Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"
Link: <http://www.w3.org/ns/ldp#RDFSource>; rel="type"
Link: <http://localhost:8890/DAV/home/demo/Public/ldp-books.ttl,meta>; rel="meta"; title="Metadata File"
ETag: "66a4b9f4bdf2990f914ffc08e1d7ab5f"
Content-Type: text/turtle
Content-Length: 193
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><HTML><HEAD><TITLE>201 Created</TITLE></HEAD><BODY><H1>Created</H1>Resource /DAV/home/demo/Public/ldp-books.ttl has been created.</BODY></HTML>
- Confirm that the server took the submission as LDP data with the command:
curl -HAccept:text/turtle http://localhost:8890/DAV/home/demo/Public/ldp-books.ttl
- The server response should be of the form:
$ curl -HAccept:text/turtle http://localhost:8890/DAV/home/demo/Public/ldp-books.ttl
@prefix ns0: <http://example.org/ns#> .
@prefix ns1: <http://example.org/book/> .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix ldp: <http://www.w3.org/ns/ldp#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
ns1:book1
ns0:price 42 ;
ns0:discount 0.2 ;
dc:title "LDP Tutorial" .
ns1:book2
ns0:price 23 ;
ns0:discount 0.25 ;
dc:title "The Semantic Web" .
<http://localhost:8890/DAV/home/demo/Public/ldp-books.ttl>
rdf:type ldp:RDFSource , rdfs:Resource , ldp:Resource .
Example 4: Access Resources in an LDPC (e.g., a DAV folder)
- Request all
LDP
data for anLDPC
, such as theDAV/home/demo/Public
folder, to be returned as Turtle –
curl -HAccept:text/turtle http://localhost:8890/DAV/home/demo/Public/
- The server response should be of the form:
$ curl -HAccept:text/turtle http://localhost:8890/DAV/home/demo/Public/
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix ns1: <http://www.w3.org/ns/iana/media-types/text/plain#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix stat: <http://www.w3.org/ns/posix/stat#> .
@prefix ns4: <http://www.w3.org/ns/iana/media-types/text/turtle#> .
@prefix ldp: <http://www.w3.org/ns/ldp#> .
<http://localhost:8890/DAV/home/demo/Public/test2.txt>
rdf:type ns1:Resource ;
stat:mtime "2023-12-01T12:04:26.441709"^^xsd:dateTime ;
stat:size 27 .
<http://localhost:8890/DAV/home/demo/Public/ldp-books.ttl>
rdf:type ns4:Resource ;
stat:mtime "2023-12-01T10:15:21.571913"^^xsd:dateTime ;
stat:size 442 .
<http://localhost:8890/DAV/home/demo/Public/>
rdf:type ldp:BasicContainer , ldp:Container ;
ldp:contains <http://localhost:8890/DAV/home/demo/Public/test2.txt> , <http://localhost:8890/DAV/home/demo/Public/ldp-books.ttl> .
$
Example 5: Delete Resources in an LDPC (e.g., a DAV folder)
- Delete a resource from the
LDPC
with the command:
curl -iX DELETE http://localhost:8890/DAV/home/demo/Public/test2.txt -u dav:dav
- The server response should be of the form:
$ curl -iX DELETE http://localhost:8890/DAV/home/demo/Public/test2.txt -u dav:dav
HTTP/1.1 204 No Content
Server: Virtuoso/07.20.3238 (Linux) x86_64-pc-linux-gnu
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
Date: Fri, 01 Dec 2023 12:39:59 GMT
Accept-Ranges: bytes
Allow: COPY, DELETE, GET, HEAD, LOCK, MKCOL, MOVE, OPTIONS, PATCH, POST, PROPFIND, PROPPATCH, PUT, TRACE, UNLOCK
Vary: Accept-Encoding, Access-Control-Request-Headers, Origin
MS-Author-Via: DAV
Accept-Post: */*
Link: <http://localhost:8890/DAV/home/demo/Public/test2.txt,meta>; rel="meta"; title="Metadata File"
Content-Length: 0
$
Example 6: Creating LDPR via POST requests
- Using an explicit target
$ curl -iX POST -H "Content-Type: text/turtle" -u dav:***-d '<#metoo> <#nick> "metoo_nick" .' "http://localhost:8890/DAV/home/demo/Public/test3.ttl"
HTTP/1.1 201 Created
Location: http://localhost:8890/DAV/home/demo/Public/test3.ttl
- Using a suggested prefix Slug HTTP header
$ curl -iX POST -H "Content-Type: text/turtle" -H"Slug: text" -u dav:*** -d '<#me> <#nick> "my_nick" .' "http://localhost:8890/DAV/home/demo/Public/"
HTTP/1.1 201 Created
Location: http://localhost:8890/DAV/home/demo/Public/text-eaa5
Note: LDP also supports JSON-LD as an alternative to Turtle, to use it replace the text/turtle
media type with application/ld+json
and the Content-Type
and use relevant documents as the input in the cURL
examples above.