A major mode for emacs that provides syntax highlighting for SPARQL. It also provides a way to execute queries against a SPARQL HTTP endpoint, such as is provided by Fuseki. It is also possible to query other endpoints like DBPedia.
- Download sparql-mode and put it in a directory somewhere.
- Add the following to your .emacs file
(add-to-list 'load-path "/path/to/sparql-mode-dir")
(autoload 'sparql-mode "sparql-mode.el"
"Major mode for editing SPARQL files" t)
(add-to-list 'auto-mode-alist '("\\.sparql$" . sparql-mode))
(add-to-list 'auto-mode-alist '("\\.rq$" . sparql-mode))
Now sparql-mode will load whenever you visit a file whose name ends
with .sparql. Alternatively, run M-x sparql-mode
in an existing
buffer containing SPARQL commands.
It is also possible to add
-*- mode: sparql -*-
to the top of the file. This is a comment read by emacs to discover what mode to use.
SPARQL-mode has basic support for both auto-complete-mode
and
company-mode
. Just add your favourite completion mode to
sparql-mode-hook
.
(add-hook 'sparql-mode-hook 'your-favourite-completion-mode)
From a buffer that is in sparql-mode, execute M-x
sparql-query-region
. You will be prompted for a SPARQL HTTP
endpoint in the minibuffer, which defaults to
http://localhost:2020/
. Once set, it will be used for all
subsequent queries in that buffer. Results will be displayed in
another buffer in CSV format.
It is also possible to use sparql-mode
with org-mode and executing
queries with org-babel. You can do that by adding the following
snippet or adding (sparql . t)
to languages org-babel can load:
(org-babel-do-load-languages
'org-babel-load-languages
'((sparql . t)))
You can then execute the query by pressing C-c C-c
on the
source-block header.
By default results formatted as text/csv
will be converted to an
org table. This can be disabled by adding :results scalar
to the
header. See examples.
Default behaviour for results in csv is to convert the result to a table:
#+BEGIN_SRC sparql :url http://live.dbpedia.org/sparql :format text/csv
SELECT DISTINCT ?Concept WHERE {
[] a ?Concept
} LIMIT 5
#+END_SRC
#+RESULTS:
| Concept |
|------------------------------------------------------------------|
| http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat |
| http://www.openlinksw.com/schemas/virtrdf#QuadStorage |
| http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat |
| http://www.openlinksw.com/schemas/virtrdf#QuadMap |
| http://www.openlinksw.com/schemas/virtrdf#QuadMapValue |
If you don’t want to convert the result to a table, you can
override that behaviour by specifying that the result should be
scalar
:
#+HEADER: :url http://live.dbpedia.org/sparql
#+HEADER: :format text/csv
#+HEADER: :results scalar
#+BEGIN_SRC sparql
SELECT DISTINCT ?Concept WHERE {
[] a ?Concept
} LIMIT 5
#+END_SRC
#+RESULTS:
: "Concept"
: "http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat"
: "http://www.openlinksw.com/schemas/virtrdf#QuadStorage"
: "http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat"
: "http://www.openlinksw.com/schemas/virtrdf#QuadMap"
: "http://www.openlinksw.com/schemas/virtrdf#QuadMapValue"
We can also declare variables that will then be expanded before execution. For example the following query:
SELECT * WHERE {
?x foaf:name ?name.
$x foaf:email ?email.
}
will be transformed into the following before it is executed:
SELECT * WHERE {
friend:Julia foaf:name ?name.
friend:Julia foaf:email ?email.
}
Notice that $x
and ?x
are treated as identical. This is
because SPARQL treats them as identical.
By combining this with the #+call
syntax we can create and reuse
queries:
#+NAME: count-statements-in-graph
#+BEGIN_SRC sparql :var graph="<>"
SELECT COUNT(*) WHERE {
GRAPH $graph {
?s ?p ?o .
}
}
#+END_SRC
#+CALL: count-statements-in-graph("<http://example.com/my-graph>")
#+RESULTS:
: "callret-0"
: 1100
#+CALL: count-statements-in-graph("<http://example.com/my-other-graph>")
#+RESULTS:
: "callret-0"
: 100
Notice that the server request is done synchronously and will therefore lock the editor if the request takes a long time.
If you have a problem or would like to see it get better in a specific way, feel free to drop an issue in the issue tracker. Enjoy!