Warning: This document is for an old version of RDFox. The latest version is 7.2.

3. Getting Started

This page will guide you through running RDFox for the first time.

3.1. Setup

Before you begin, make sure that you have downloaded the latest RDFox release for your system from www.oxfordsemantic.tech/downloads and unpacked it into a directory of your choosing. The following instructions refer to the directory as <working_directory>. You will also need to ensure that RDFox can find a valid license key. The quickest way to do this is to add a copy of your license key file directly to <working_directory> (see Section 2.4.3 for other ways). If you do not have a license key file, you can request one at https://www.oxfordsemantic.tech/tryrdfoxforfree.

The following small RDF graph in Turtle format is used in the instructions below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@prefix : <https://oxfordsemantic.tech/RDFox/getting-started/> .

:peter :forename "Peter" ;
    a :Person ;
    :marriedTo :lois ;
    :gender "male" .

:lois :forename "Lois" ;
    a :Person ;
    :gender "female" .

:meg :forename "Meg" ;
    a :Person ;
    :hasParent :lois, :peter ;
    :gender "female" .

:chris :forename "Chris" ;
    a :Person ;
    :hasParent :peter ;
    :gender "male" .

:stewie :forename "Stewie" ;
    a :Person ;
    :hasParent :lois ;
    :gender "male" .

:brian :forename "Brian" . # Brian is a dog

Download data.ttl into <working_directory>

In a terminal, change to <working_directory> and then launch the RDFox shell as follows:

./RDFox sandbox
RDFox.exe sandbox

You should be presented with a command prompt where you can run any of the commands described in Section 16.2.2.

RDFox exposes a REST API which includes a SPARQL over HTTP endpoint. Start the endpoint with:

endpoint start

which will print the port number it is listening on.

The REST endpoint was successfully started at port number/service name 12110 with 7 threads.

The endpoint also serves a web-based console application that itself uses the REST API.

Continue the Getting Started tutorial with the shell (Section 3.2), the web console (Section 3.3) or the REST API (Section 3.4).

3.2. Getting Started with the Shell

Ensure all steps from the Setup chapter have been completed.

3.2.1. Creating a Data Store

All facts and rules in RDFox live inside a data store. Initially no data stores exist so we must create one before we can load any triples. To create a data store we use the dstore command as follows:

dstore create family

The above command initializes our family data store. To ensure that subsequent shell commands address our new data store, we use the active command to tell the shell to connect to the family data store when running commands that address a data store:

active family

3.2.2. Importing Data

Import the data.ttl in the <working_directory> into the active data store with:

import data.ttl

This command should report the time taken by the import and that 21 data items have been loaded from the file.

3.2.3. Running Queries

By default, RDFox does not specify where query answers must be sent. To instruct RDFox to print answers to the terminal, run the following command:

set output out

Define the : prefix in the shell, to simplify several of the subsequent commands, with:

PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/>

You are now ready to run your first query!

The primary query language recognized by RDFox is SPARQL. SPARQL queries can be typed or pasted directly into the shell.

Copy and paste the following SPARQL into the shell and hit enter to print all of the triples in the store:

SELECT ?s ?p ?o WHERE { ?s ?p ?o }

You should see a few lines beginning @prefix followed by a blank line and then the original 21 triples (facts) from data.ttl. After the triples, a summary of the number of answers returned and the time taken for the query is printed.

Note that the Turtle snippet is in a slightly different format to the answers, so the answers do not exactly match the file contents. Taking time now to satisfy yourself that the query answers really do contain the same information as data.ttl will be a good way to gain familiarity with the Turtle syntax. In addition, it helps to know that a single a character in the predicate position of a triple represents http://www.w3.org/1999/02/22-rdf-syntax-ns#type which denotes an entity’s type and will often appear as rdf:type.

To demonstrate a simple conjunction, print each person’s forename:

SELECT ?p ?n WHERE { ?p rdf:type :Person . ?p :forename ?n }

Note that :brian is not returned as this entity is not of type :Person as required by the first part of the where clause.

3.2.4. Inserting Data Using SPARQL

It is also possible to modify the contents of the data store via queries. For example, make the :marriedTo relationship symmetric:

INSERT { ?x :marriedTo ?y } WHERE { ?y :marriedTo ?x }

This adds one new triple to the data store reflecting the fact that Lois is married to Peter, which was derived from the fact that Peter is married to Lois. Rerunning the first SELECT query from Section 3.2.3 should now return 22 triples (use the up arrow key to step back through your command history to find the first SELECT command).

3.2.5. Adding Rules

Reasoning is the ability to calculate the logical consequences of applying a set of rules to a set of facts. To illustrate how this can be useful, consider the calculation of the number of children for each parent. The above data has the opposite information - i.e. only :hasParent relationships - so querying for :hasChild, though more natural for our use case, will turn up no results. We could remodel the data but this could make the phrasing of any queries about parents less natural. We could add all the :hasChild relationships as new facts in the Turtle file but the dataset would then have a bunch of redundancy and we would need to make sure that we always add both relationships together when we add new people to the dataset.

With reasoning we can have the best of both worlds. Keeping the original dataset, we add a rule to state that if ?c has a parent ?p then ?p has a child ?c. RDFox can then determine all of the :hasChild relationships itself - including for any new families that we add later on.

RDFox uses the Datalog language for expressing rules. The above rule can be added with the following command:

import ! [?p, :hasChild, ?c] :- [?c, :hasParent, ?p] .

To check that we now have some triples with :hasChild as the predicate, evaluate the following query:

SELECT ?p ?c WHERE { ?p :hasChild ?c }

Four results are returned, all of which have been added by RDFox by evaluating the rule defined above.

3.2.6. Deleting Facts

To check that the rule really is ‘live’, delete the triple that says :stewie has :lois as a parent by running:

DELETE DATA { :stewie :hasParent :lois }

Now re-query the triples using the :hasChild property with:

SELECT ?p ?c WHERE { ?p :hasChild ?c }

and observe that the answer :lois :stewie ., which was derived from the combination of the rule we added and the fact we just deleted, no longer appears.

3.2.7. Stopping and Re-starting RDFox

Shut down RDFox by typing the quit command. Since RDFox is an in-memory database, and because we started the process using the sandbox command which disables any form of persistence, the contents of the data store will be dropped when the process exits. While experimenting with RDFox, it may therefore be useful to write the commands to initialize the data store and load data into a script which can be passed to RDFox at startup. The following script repeats the whole of this tutorial. Save it to a new file <working_directory>/start.rdfox and then run it with ./RDFox sandbox . start (on Linux or Mac) or RDFox.exe sandbox . start (on Windows).

endpoint start
dstore create family
active family
import data.ttl
set output out
prefix : <https://oxfordsemantic.tech/RDFox/getting-started/>
SELECT ?s ?p ?o WHERE { ?s ?p ?o }
SELECT ?p ?n WHERE { ?p rdf:type :Person . ?p :forename ?n }
INSERT { ?x :marriedTo ?y } WHERE { ?y :marriedTo ?x }
import ! [?p, :hasChild, ?c] :- [?c, :hasParent, ?p] .
SELECT ?p ?c WHERE { ?p :hasChild ?c }
DELETE DATA { :stewie :hasParent :lois }
SELECT ?p ?c WHERE { ?p :hasChild ?c }

For alternative ways of starting RDFox which do not disable persistence, see Section 16.

3.3. Getting Started with the Web Console

The console supports the creation, population and querying of RDFox data stores.

Ensure all steps from the Setup chapter have been completed.

Download the file symmetry.dlog containing a single Datalog rule, which specifies that the marriedTo relationship is symmetric, to the same <working_directory> as data.ttl above.

@prefix : <https://oxfordsemantic.tech/RDFox/getting-started/> .
[?b, :marriedTo, ?a] :- [?a, :marriedTo, ?b] .

Download: symmetry.dlog.

In a web browser, navigate to http://localhost:12110/console/.

3.3.1. Creating a Data Store

Create the data store called family by clicking CreateDataStoreHeader on the header to display a dialog, entering the name “family” in the text field, and clicking the CreateDataStore button on the dialog. This creates, and immediately selects, a data store of type par-complex-nn.

3.3.2. Importing Data

On successfully creating the data store, the console displays an option to import data into the data store. Click ImportContent to display the “Add content” dialog.

Drag the data files data.ttl and symmetry.dlog from the <working_directory> onto the dialog.

Click AddContent to confirm no further data files are to be added now, and to proceed with the import.

A status report of the number of facts (21) and rules (1) added to the new data store is displayed. Dismiss the report by clicking OK.

3.3.3. Running Queries

The newly created data store is automatically selected and so the SPARQL query editor is enabled. In the query editor pane, replace the default query:

PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/>
SELECT ?spouse1 ?spouse2
WHERE {
  ?spouse1 :marriedTo ?spouse2
}
ORDER BY ?spouse1

Click RunQuery to make the console run the query over REST and display the answers. You should see:

spouse1

spouse2

:lois

:peter

:peter

:lois

3.3.4. Exploring a Data Store

Click the Explore icon to the right of :peter to switch to the “Explore” mode and visually explore the data store starting from that individual.

The dot icon in the upper right of the purple peter node indicates that there are links present in the data store that are not being visualized. Right-click the node to display a context menu of the seven connections between :peter and other entities in this data store.

Select gender male and lois marriedTo from the menu and click “Expand”. The link to the literal male is displayed, as are both links between lois and peter.

3.3.5. Deleting Data

The procedure for deleting of facts, axioms and rules is similar to that for adding data.

Click the Menu button in the header and click the “Delete content” option.

The “Delete content” dialog allows facts, axioms and rules to be removed from the selected data store. Drag the symmetry.dlog file added earlier onto the dialog.

Click DeleteContent to remove the datalog rule from the active data store and click OK to dismiss the report.

Click Query in the header to return to the query view. Click RunQuery. Because the rule has been removed from the family data store, the triple added by that rule has been removed and so the same query returns a single result:

spouse1

spouse2

:peter

:lois

3.3.6. Deleting a Data Store

To delete the currently selected data store:

Click the Menu button in the header and click the “Delete data store” option.

Click Delete to confirm that the active data store and its contents will be deleted. After family is deleted, no data store is selected.

Note that, at present, the web-based console is an experimental feature.

3.4. Getting Started with the REST API

For remote use, RDFox exposes a REST API which includes a SPARQL-over-HTTP endpoint. We show how to use the REST API to achieve the same results as Getting Started with the Shell.

The step-by-step examples use the cURL tool which is normally installed on MacOS, Linux and modern versions of Windows. At the end of this section, we give an example of achieving the same results using Python.

Ensure all steps from the Setup chapter have been completed.

3.4.1. Creating a Data Store

To perform the equivalent of the RDFox shell commands dstore create family par-complex-nn we issue a POST request on the datastore/family path specifying the type of data store in the type query parameter.

curl -i -X POST "localhost:12110/datastores/family?type=par-complex-nn"

Note we run cURL with the -i option to include the response headers in the output which means the output will be similar to:

HTTP/1.1 201 Created
Date: Fri, 12 Jul 2019 12:13:32 GMT
Server: RDFox Endpoint
Location: /datastores/family
Content-Length: 0

We can confirm this data store exists by listing the data stores using a GET request on the datastores path:

curl -i -X GET localhost:12110/datastores

The results will be:

HTTP/1.1 200 OK
Date: Fri, 12 Jul 2019 12:15:04 GMT
Server: RDFox Endpoint
Content-Type: text/tab-separated-values; charset=UTF-8
Transfer-Encoding: chunked

?Name
"family"

3.4.2. Loading Data

To load data, we perform the equivalent of the import RDFox shell command shown in Section 3.1 by issuing a POST on the datastores/family/content path.

There is no mechanism to import a file that is located on the server, instead the data content must be sent in the body of the request. We can achieve this with cURL by creating a file and using the -data command line option to read this file and send it to RDFox.

Using the data file data.ttl, issue the cURL command:

curl -i -X POST localhost:12110/datastores/family/content -H "Content-Type:" -T data.ttl

This sends the turtle data to RDFox and reports success with:

HTTP/1.1 200 OK
Date: Fri, 12 Jul 2019 13:16:11 GMT
Server: RDFox Endpoint
Content-Type: text/plain; charset=UTF-8
Transfer-Encoding: chunked

prefix: : = https://oxfordsemantic.tech/RDFox/getting-started/
information: #facts = 21

Note the use of -H "Content-Type:" in the cURL command. By default, cURL will set the content type to application/x-www-form-urlencoded which is a not a supported RDFox Content-Type. Using -H "Content-Type:" instructs cURL not to set the Content-Type and allows RDFox to automatically detect that we have data in Turtle format. Alternatively, we could explicitly set the type using -H "Content-Type: text/turtle". For the different formats supported by RDFox, see Section 14.3.

3.4.3. Listing Triples

To list the triples in the data store, we send a GET request to the content path and use the Accept request header to obtain the results in Turtle.

curl -i -X GET localhost:12110/datastores/family/content -H "Accept: text/turtle"

which returns:

HTTP/1.1 200 OK
Date: Fri, 12 Jul 2019 13:16:41 GMT
Server: RDFox Endpoint
Content-Type: text/turtle; charset=UTF-8
Transfer-Encoding: chunked

@prefix a1: <https://oxfordsemantic.tech/RDFox/getting-started/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix ruleml: <http://www.w3.org/2003/11/ruleml#> .
@prefix swrl: <http://www.w3.org/2003/11/swrl#> .
@prefix swrlb: <http://www.w3.org/2003/11/swrlb#> .
@prefix swrlx: <http://www.w3.org/2003/11/swrlx#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

a1:peter a1:gender "male" ;
    a1:marriedTo a1:lois ;
    rdf:type a1:Person ;
    a1:forename "Peter" .

a1:lois a1:gender "female" ;
    rdf:type a1:Person ;
    a1:forename "Lois" .

a1:meg a1:gender "female" ;
    a1:hasParent a1:lois , a1:peter ;
    rdf:type a1:Person ;
    a1:forename "Meg" .

a1:chris a1:gender "male" ;
    a1:hasParent a1:peter ;
    rdf:type a1:Person ;
    a1:forename "Chris" .

a1:stewie a1:gender "male" ;
    a1:hasParent a1:lois ;
    rdf:type a1:Person ;
    a1:forename "Stewie" .

a1:brian a1:forename "Brian" .

Alternatively we could list the triples in N-Triples format with:

curl -i -X GET localhost:12110/datastores/family/content -H "Accept: application/n-triples"

3.4.4. Running Queries

To run a query we send a POST request to the sparql path and set the query parameter to a SPARQL query. To run the query SELECT ?p ?n WHERE { ?p a :Person . ?p :forename ?n } we run the command:

curl -i -X POST localhost:12110/datastores/family/sparql -d "query=PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/>  SELECT ?p ?n WHERE { ?p a :Person . ?p :forename ?n }"

This returns the result in the default format of tab-separated-values.

HTTP/1.1 200 OK
Date: Mon, 22 Jul 2019 16:05:56 GMT
Server: RDFox Endpoint
Content-Type: text/tab-separated-values; charset=UTF-8
Transfer-Encoding: chunked

?p      ?n
<https://oxfordsemantic.tech/RDFox/getting-started/peter>       "Peter"
<https://oxfordsemantic.tech/RDFox/getting-started/stewie>      "Stewie"
<https://oxfordsemantic.tech/RDFox/getting-started/chris>       "Chris"
<https://oxfordsemantic.tech/RDFox/getting-started/meg> "Meg"
<https://oxfordsemantic.tech/RDFox/getting-started/lois>        "Lois"

To view the results in SPARQL 1.1 JSON Format set the Accept header to application/sparql-results+json:

curl -i -X POST -H "Accept: application/sparql-results+json" localhost:12110/datastores/family/sparql -d "query=PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/>  SELECT ?p ?n WHERE { ?p a :Person . ?p :forename ?n }"

Notice the use of query=... in the post data. This is necessary because cURL will URL-encode post data by default and the SPARQL standard requires the query parameter is used when issuing a SPARQL query via POST with URL-encoded parameters Alternatively it is possible to issue a query via POST directly by setting the content type to application/sparql-query as shown below:

curl -i -X POST localhost:12110/datastores/family/sparql -H "Content-Type: application/sparql-query"  -d "PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/>  SELECT ?p ?n WHERE { ?p a :Person . ?p :forename ?n }"

3.4.5. Inserting Data Using SPARQL

To perform a SPARQL insert the update parameter should be used:

curl -i -X POST localhost:12110/datastores/family/sparql -d "update=PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/> INSERT { ?x :marriedTo ?y } WHERE { ?y :marriedTo ?x }"

this returns the no content (204) status code to indicate success:

HTTP/1.1 204 No Content
Date: Mon, 22 Jul 2019 16:06:47 GMT
Server: RDFox Endpoint

3.4.6. Adding Rules

To add a Datalog rule we issue a POST request to the content path and send the rule text in the body of the request:

curl -i -X POST localhost:12110/datastores/family/content -H "Content-Type: application/x.datalog" --data-raw "@PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/> . [?p, :hasChild, ?c] :- [?c, :hasParent, ?p] ."

this returns the OK status code (200) to indicate success:

HTTP/1.1 200 OK
Date: Mon, 22 Jul 2019 16:07:49 GMT
Server: RDFox Endpoint
Content-Type: text/plain; charset=UTF-8
Transfer-Encoding: chunked

prefix: : = https://oxfordsemantic.tech/RDFox/getting-started/
information: #rules = 1
information: #rule-updates = 1

Note the use of the --data-raw option in the above example, this is because normally @ means insert the contents of a file in cURL, using --data-raw allows @ symbols to be sent as is.

To confirm this rule has added new facts issue a SELECT ?p ?c WHERE { ?p :hasChild ?c } query with:

curl -i -X GET -H "Accept: application/x.sparql-results+turtle" localhost:12110/datastores/family/sparql -d "query=PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/> SELECT ?p ?c WHERE { ?p :hasChild ?c }"

this returns an OK status code (200) and the results of the query in Turtle format:

HTTP/1.1 200 OK
Date: Mon, 22 Jul 2019 16:08:48 GMT
Server: RDFox Endpoint
Content-Type: application/x.sparql-results+turtle; charset=UTF-8
Transfer-Encoding: chunked

<https://oxfordsemantic.tech/RDFox/getting-started/lois> <https://oxfordsemantic.tech/RDFox/getting-started/meg> .
<https://oxfordsemantic.tech/RDFox/getting-started/peter> <https://oxfordsemantic.tech/RDFox/getting-started/meg> .
<https://oxfordsemantic.tech/RDFox/getting-started/peter> <https://oxfordsemantic.tech/RDFox/getting-started/chris> .
<https://oxfordsemantic.tech/RDFox/getting-started/lois> <https://oxfordsemantic.tech/RDFox/getting-started/stewie> .

3.4.7. Deleting Facts

To prove the :hasChild rule is live, delete the fact [:stewie :hasParent :lois]. We achieve this by sending a PATCH request to the content path and setting the operation parameter to delete-content:

curl -i -X PATCH -H "Content-Type: application/x.datalog" "localhost:12110/datastores/family/content?operation=delete-content" --data-raw "@PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/> . [:stewie, :hasParent, :lois] ."

When the SELECT ?p ?c WHERE { ?p :hasChild ?c } query is rerun with:

curl -i -X GET -H "Accept: application/x.sparql-results+turtle" localhost:12110/datastores/family/sparql -d "query=PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/> SELECT ?p ?c WHERE { ?p :hasChild ?c }"

we see that the result :lois, :stewie is no longer present:

HTTP/1.1 200 OK
date: Wed, 24 Jul 2019 16:59:38 GMT
server: RDFox Endpoint
content-type: application/x.sparql-results+turtle; charset=UTF-8
transfer-encoding: chunked

<https://oxfordsemantic.tech/RDFox/getting-started/lois> <https://oxfordsemantic.tech/RDFox/getting-started/meg> .
<https://oxfordsemantic.tech/RDFox/getting-started/peter> <https://oxfordsemantic.tech/RDFox/getting-started/meg> .
<https://oxfordsemantic.tech/RDFox/getting-started/peter> <https://oxfordsemantic.tech/RDFox/getting-started/chris> .

3.4.8. Deleting a Data Store

To perform the equivalent of the RDFox shell command dstore delete family force we issue a DELETE request on the datastore/family path.

curl -i -X DELETE "localhost:12110/datastores/family"

3.4.9. Python example

The following Python script uses the requests module to reproduce the same steps as used in the cURL examples presented previous.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import requests

# helper function to raise exception if the REST endpoint returns an
# unexpected status code
def assert_reponse_ok(response, message):
    if not response.ok:
        raise Exception(
            message + "\nStatus received={}\n{}".format(response.status_code, response.text))

rdfox_server = "http://localhost:12110"

# Create the data store
response = requests.post(
    rdfox_server + "/datastores/family", params={'type': 'par-complex-nn'})
assert_reponse_ok(response, "Failed to create datastore.")

# List data stores
response = requests.get(rdfox_server + "/datastores")
assert_reponse_ok(response, "Failed to obtain list of datastores")
print("== Data store list ==")
print(response.text)

# Add facts
turtle_data = """
@prefix : <https://oxfordsemantic.tech/RDFox/getting-started/> .

:peter :forename "Peter" ;
    a :Person ;
    :marriedTo :lois ;
    :gender "male" .

:lois :forename "Lois" ;
    a :Person ;
    :gender "female" .

:meg :forename "Meg" ;
    a :Person ;
    :hasParent :lois, :peter ;
    :gender "female" .

:chris :forename "Chris" ;
    a :Person ;
    :hasParent :peter ;
    :gender "male" .

:stewie :forename "Stewie" ;
    a :Person ;
    :hasParent :lois ;
    :gender "male" .

:brian :forename "Brian" . # Brian is a dog
"""

response = requests.post(
    rdfox_server + "/datastores/family/content", data=turtle_data)
assert_reponse_ok(response, "Failed to add facts to data store.")

# List facts
response = requests.get(
    rdfox_server + "/datastores/family/content", headers={"Accept": "text/turtle"})
assert_reponse_ok(response, "Failed to obtain facts from data store.")
print("== Facts imported ==")
print(response.text)

# Issue select query
sparql_text = "PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/> " \
    "SELECT ?p ?n WHERE { ?p a :Person . ?p :forename ?n }"
response = requests.get(
    rdfox_server + "/datastores/family/sparql", params={"query": sparql_text})
assert_reponse_ok(response, "Failed to run select query.")
print("== Initial query result ==")
print(response.text)

# Issue insert
sparql_insert = "PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/> " \
    "INSERT { ?x :marriedTo ?y } WHERE { ?y :marriedTo ?x }"
response = requests.post(
    rdfox_server + "/datastores/family/sparql", data={"update": sparql_insert})
assert_reponse_ok(response, "Failed to insert fact via sparql.")

# Add rule
datalog_rule = "@PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/> . " \
    "[?p, :hasChild, ?c] :- [?c, :hasParent, ?p] ."
response = requests.post(
    rdfox_server + "/datastores/family/content", data=datalog_rule)
assert_reponse_ok(response, "Failed to add rule.")

# Check rule exists by listing rules.
response = requests.get(rdfox_server + "/datastores/family/content",
                        headers={"Content-Type": "application/x.datalog"})
assert_reponse_ok(response, "Failed to list rules.")
print("== Rules listing (after adding rule) ==")
print(response.text)

# Query to confirm rule
sparql_text = "PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/> " \
    "SELECT ?p ?c WHERE { ?p :hasChild ?c }"
response = requests.get(
    rdfox_server + "/datastores/family/sparql", params={"query": sparql_text})
assert_reponse_ok(response, "Failed to run select query.")
print("== Query for derived facts ==")
print(response.text)

# Delete fact
datalog_text = "@PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/> . " \
    "[:stewie, :hasParent, :lois] ."
response = requests.patch(
    rdfox_server + "/datastores/family/content", params={"operation": "delete-content"}, data=datalog_text)
assert_reponse_ok(response, "Failed to delete fact.")

# Query to confirm derived facts updated (stewie is no longer a child of lois)
sparql_text = "PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/> " \
    "SELECT ?p ?c WHERE { ?p :hasChild ?c }"
response = requests.get(
    rdfox_server + "/datastores/family/sparql", params={"query": sparql_text})
assert_reponse_ok(response, "Failed to run select query.")
print("== Query for updated derived facts ==")
print(response.text)

# delete rule
datalog_rule = "@PREFIX : <https://oxfordsemantic.tech/RDFox/getting-started/> . " \
    "[?p, :hasChild, ?c] :- [?c, :hasParent, ?p] ."
response = requests.patch(
    rdfox_server + "/datastores/family/content", params={"operation": "delete-content"}, data=datalog_rule)
assert_reponse_ok(response, "Failed to delete rule.")

# list rules after deletion
response = requests.get(rdfox_server + "/datastores/family/content",
                        headers={"Accept": "application/x.datalog"})
assert_reponse_ok(response, "Failed to list rules.")
print("== Rules listing (after deleting rule) ==")
print(response.text)

# Delete the data store
response = requests.delete(
    rdfox_server + "/datastores/family")
assert_reponse_ok(response, "Failed to delete data store.")

Download: pythonRest.py.