swish/commit
ADDED: CSV client support
author | Jan Wielemaker |
---|---|
Fri Mar 6 16:16:11 2015 +0100 | |
committer | Jan Wielemaker |
Fri Mar 6 16:16:11 2015 +0100 | |
commit | ea259dc12482779ddd4434137e9e54362ee73be6 |
tree | affde956589302cc6d9b4c9d3795a93177bed444 |
parent | b080ebfb870634cdeffd388d68ecf44bd8c4341c |
Diff style: patch stat
diff --git a/Makefile b/Makefile index 392accd..095b54a 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ # Create a ClioPatria SWISH package from the SWISH distribution. FONTDIR=web/bower_components/bootstrap/dist/fonts -DIRS=lib/swish lib/swish/render web/icons web/help $(FONTDIR) +DIRS=lib/swish lib/swish/render web/icons web/help client $(FONTDIR) SWISHLIB=storage.pl page.pl help.pl examples.pl config.pl gitty.pl \ highlight.pl render.pl template_hint.pl search.pl form.pl \ - include.pl + include.pl csv.pl RENDER=table.pl LIBS= $(addprefix lib/swish/, $(SWISHLIB)) \ $(addprefix lib/swish/render/, $(RENDER)) @@ -16,14 +16,19 @@ HELP=$(addprefix web/help/, $(notdir $(wildcard src/web/help/*.html))) FONTFILES=glyphicons-halflings-regular.ttf \ glyphicons-halflings-regular.woff FONTS=$(addprefix $(FONTDIR)/, $(FONTFILES)) +CLIENTFILES=swish-ask.sh +CLIENTS=$(addprefix client/, $(CLIENTFILES)) -all: $(DIRS) $(LIBS) $(JS) $(CSS) $(ICONS) $(HELP) $(FONTS) +all: $(DIRS) $(LIBS) $(JS) $(CSS) $(ICONS) $(HELP) $(FONTS) $(CLIENTS) $(DIRS): mkdir -p $@ lib/swish/%: src/lib/% rsync -u $< $@ +client/%: src/client/% + sed -e 's/:3050}/:3020}/' -e 's/-prolog}/-rdf}/' $< > $@ + chmod +x $@ web/js/swish-min.js: src/web/js/swish-min.js rsync -u $< $@ diff --git a/applications/swish.pl b/applications/swish.pl index ff6c135..bee004e 100644 --- a/applications/swish.pl +++ b/applications/swish.pl @@ -34,11 +34,13 @@ :- use_module(library(http/http_dispatch)). :- use_module(library(http/http_server_files)). :- use_module(library(http/http_json)). +:- use_module(rdfql(sparql_csv_result)). :- use_module(library(swish/config)). :- use_module(library(swish/page), []). :- use_module(library(swish/storage)). :- use_module(library(swish/include)). +:- use_module(library(swish/csv)). :- use_module(library(swish/examples)). :- use_module(library(swish/help)). :- use_module(library(swish/highlight)). @@ -68,6 +70,21 @@ swish_config:config(tabled_results, true). swish_config:config(application, swish). + /******************************* + * CSV * + *******************************/ + +:- multifile swish_csv:write_answers/2. + +swish_csv:write_answers(Answers, VarTerm) :- + Answers = [H|_], + functor(H, rdf, _), !, + sparql_write_csv_result( + current_output, + select(VarTerm, Answers), + []). + + /******************************* * CREATE SWISH APPLICATION * *******************************/ diff --git a/client/swish-ask.sh b/client/swish-ask.sh new file mode 100755 index 0000000..d009dd5 --- /dev/null +++ b/client/swish-ask.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# +# Ask information from a Pengines/SWISH server from the shell. +# +# This program allows you to download query results from a SWISH server +# as CSV data. + +server=${SWISH_SERVER-http://localhost:3020} +srctext= +format=${SWISH_FORMAT-rdf} +program=$(basename $0) + +usage() +{ +cat << _EOM_ +Usage: $program "[--server=URL] [--format=rdf|prolog]" file.pl ... projection query + +Where + + - server is by default "$server". Environment: SWISH_SERVER + - format is by default "$format". Environment: SWISH_FORMAT + - file.pl ... are files saved in SWISH. Zero or more files are allowed + - projection is a comma-separated list of Prolog variables that define + the CSV columns. + - query is a Prolog goal using the variables from projection. + +For example + + $program X 'X is 1<<100' + X + 1267650600228229401496703205376 + + $program factbook.pl Code,Country 'country(Country,Code)' + Code,Country + af,http://www4.wiwiss.fu-berlin.de/factbook/resource/Afghanistan + ax,http://www4.wiwiss.fu-berlin.de/factbook/resource/Akrotiri + ... +_EOM_ +} + +done=false +while [ $done = false ]; do + case "$1" in + --server=*) + server=$(echo $1 | sed 's/.*=//') + shift + ;; + --format=*) + format=$(echo $1 | sed 's/.*=//') + case "$format" in + rdf|prolog) + ;; + *) + usage + exit 1 + ;; + esac + shift + ;; + *.pl) + script=$(echo $1 | sed 's/.*=//') + srctext+=":- include('$script'). " + shift + ;; + *) + done=true + ;; + esac +done + +vars="$1" +query="$2" + +if [ -z "$vars" -o -z "$query" ]; then + usage + exit 1 +fi + +curl -s \ + -d ask="$query" \ + -d template="$format($vars)" \ + -d application="swish" \ + -d src_text="$srctext" \ + -d format=csv \ + -d chunk=100000000 \ + $server/pengine/create diff --git a/lib/swish/csv.pl b/lib/swish/csv.pl new file mode 100644 index 0000000..88b484b --- /dev/null +++ b/lib/swish/csv.pl @@ -0,0 +1,109 @@ +/* Part of SWI-Prolog + + Author: Jan Wielemaker + E-mail: J.Wielemaker@cs.vu.nl + WWW: http://www.swi-prolog.org + Copyright (C): 2015, VU University Amsterdam + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + As a special exception, if you link this library with other files, + compiled with a Free Software compiler, to produce an executable, this + library does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however + invalidate any other reasons why the executable file might be covered by + the GNU General Public License. +*/ + +:- module(swish_csv, []). +:- use_module(library(pengines), []). +:- use_module(library(pairs)). +:- use_module(library(csv)). +:- use_module(library(apply)). +:- use_module(library(pprint)). + +/** <module> Support CSV output from a Pengines server + +This module defines the result-format `csv` for Pengines. It allows +SWISH users to post a query against the core Prolog system or a saved +SWISH program and obtain the results using a simple web client such as +`curl`. An example shell script is provided in =client/swish-ask.sh=. + +@tbd Provide streaming output +*/ + +:- multifile + pengines:write_result/3, + write_answers/2. + +%% pengines:write_result(+Format, +Event, +VarNames) is semidet. +% +% Hook into library(pengines) that makes pengines support CSV +% output. + +pengines:write_result(csv, Event, VarNames) :- + csv(Event, VarNames). + +csv(create(_Id, Features), VarNames) :- !, + memberchk(answer(Answer), Features), + csv(Answer, VarNames). +csv(destroy(_Id, Wrapped), VarNames) :- !, + csv(Wrapped, VarNames). +csv(success(_Id, Answers, _Time, _More), VarNames) :- !, + VarTerm =.. [row|VarNames], + success(Answers, VarTerm). +csv(error(_Id, Error), _VarNames) :- !, + message_to_string(Error, Msg), + format('Status: 400 Bad request~n'), + format('Content-type: text/plain~n~n'), + format('ERROR: ~w~n', [Msg]). +csv(output(_Id, message(_Term, _Class, HTML, _Where)), _VarNames) :- !, + format('Status: 400 Bad request~n'), + format('Content-type: text/html~n~n'), + format('<html>~n~s~n</html>~n', [HTML]). +csv(Event, _VarNames) :- + print_term(Event, [output(user_error)]). + +success(Answers, VarTerm) :- + write_answers(Answers, VarTerm), !. +success(Answers, VarTerm) :- + maplist(csv_answer, Answers, Rows), + format('Content-type: text/csv~n~n'), + csv_write_stream(current_output, [VarTerm|Rows], []). + +csv_answer(JSON, Row) :- + is_dict(JSON), !, + dict_pairs(JSON, _, Pairs), + pairs_values(Pairs, Values), + maplist(csv_value, Values, CVSValues), + Row =.. [row|CVSValues]. +csv_answer(RowIn, Row) :- + compound(RowIn), !, + RowIn =.. [_|Values], + maplist(csv_value, Values, CVSValues), + Row =.. [row|CVSValues]. + +csv_value(Var, '') :- + var(Var), !. +csv_value(Number, Number) :- + number(Number), !. +csv_value(Atom, Atom) :- + atom(Atom), !. +csv_value(String, String) :- + string(String), !. +csv_value(Term, Value) :- + term_string(Term, Value). + +