
Author: lgiessmann Date: Wed Nov 17 16:41:59 2010 New Revision: 340 Log: added a SPARQL-Query class with several accessor-methods. This class contains the actual query-string, some query-attributes and the result objects; started to implement a SPARQL-parser => currently the PREFIX parts can be processed; added some functions to base-tools Added: trunk/src/TM-SPARQL/sparql_parser.lisp - copied, changed from r336, /trunk/src/TM-SPARQL/sparql_tokenizer.lisp Removed: trunk/src/TM-SPARQL/sparql_tokenizer.lisp Modified: trunk/src/TM-SPARQL/sparql.lisp trunk/src/base-tools/base-tools.lisp trunk/src/isidorus.asd trunk/src/model/datamodel.lisp trunk/src/model/exceptions.lisp trunk/src/xml/rdf/exporter.lisp trunk/src/xml/xtm/tools.lisp Modified: trunk/src/TM-SPARQL/sparql.lisp ============================================================================== --- trunk/src/TM-SPARQL/sparql.lisp (original) +++ trunk/src/TM-SPARQL/sparql.lisp Wed Nov 17 16:41:59 2010 @@ -7,4 +7,60 @@ ;;+ trunk/docs/LGPL-LICENSE.txt. ;;+----------------------------------------------------------------------------- +(defpackage :TM-SPARQL + (:use :cl :datamodel :base-tools :exceptions) + (:export :SPARQL-Query)) + + (in-package :TM-SPARQL) + +(defvar *empty-label* "_empty_label_symbol") + + +(defclass SPARQL-Query () + ((original-query :initarg :original-query + :reader original-query + :type String + :initform (error + (make-condition + 'missing-query-string-error + :message "From TM-Query(): original-query must be set")) + :documentation "Containst the original received querry as string") + (prefix-list :initarg :prefix-list + :reader prefix-list + :type List + :documentation "A list of the form + ((:label 'id' :value 'prefix'))") + (variables :initarg :variables + :accessor :variables + :type List + :documentation "A list of the form ((:variable var-symbol + :value value-object)), that contains tuples + for each variable and its result.") + (select-statements :initarg :select-statements + :accessor select-statements + :type List + :documentation "A list of the form ((:statement 'statement' + :value value-object))"))) + + +(defgeneric add-prefix (construct prefix-label prefix-value) + (:documentation "Adds the new prefix tuple to the list of all existing. + If there already exists a tuple with the same label + the label's value will be overwritten by the new value.") + (:method ((construct SPARQL-Query) (prefix-label Symbol) (prefix-value String)) + (let ((existing-tuple + (find-if #'(lambda(x) + (eql (getf x :label) prefix-label)) + (prefix-list construct)))) + (if existing-tuple + (setf (getf existing-tuple :value) prefix-value) + (push (list :label prefix-label :value prefix-value) + (slot-value construct 'prefix-list)))))) + + + +(defmethod initialize-instance :after ((construct SPARQL-Query) &rest args) + (declare (ignorable args)) + (parser-start construct) + construct) Copied: trunk/src/TM-SPARQL/sparql_parser.lisp (from r336, /trunk/src/TM-SPARQL/sparql_tokenizer.lisp) ============================================================================== --- /trunk/src/TM-SPARQL/sparql_tokenizer.lisp (original) +++ trunk/src/TM-SPARQL/sparql_parser.lisp Wed Nov 17 16:41:59 2010 @@ -7,8 +7,113 @@ ;;+ trunk/docs/LGPL-LICENSE.txt. ;;+----------------------------------------------------------------------------- -(defpackage :TM-SPARQL - (:use :cl :datamodel)) +(in-package :TM-SPARQL) +(defun make-sparql-parser-condition(rest-of-query entire-query expected) + "Creates a spqrql-parser-error object." + (declare (String rest-of-query entire-query expected)) + (let ((message + (format nil "The query:~%~a bad token on position ~a. Expected: ~a" + entire-query (- (length entire-query) + (length rest-of-query)) + expected))) + (make-condition 'sparql-parser-error :message message))) -(in-package :TM-SPARQL) + + +(defgeneric parser-start(construct query-string) + (:documentation "The entry point of the SPARQL-parser.") + (:method ((construct SPARQL-Query) (query-string String)) + (let ((trimmed-query-string (trim-whitespace-left query-string))) + (cond ((string-starts-with trimmed-query-string "SELECT") + (parse-prefixes construct + (string-after trimmed-query-string "SELECT"))) + ((string-starts-with trimmed-query-string "PREFIX") + nil) ;TODO: implement + ((string-starts-with trimmed-query-string "BASE") + nil) ;TODO: implement + (t + (error (make-sparql-parser-condition + trimmed-query-string (original-query construct) + "SELECT, PREFIX or BASE"))))))) + + +(defgeneric parse-prefixes (construct query-string) + (:documentation "Sets the correponding prefix-tuples in the passed object.") + (:method ((construct SPARQL-Query) (query-string String)) + (let ((trimmed-string (trim-whitespace-left query-string))) + (if (string-starts-with trimmed-string ":") + (let ((results + (parse-bracket-value (subseq trimmed-string 1) construct))) + (add-prefix construct *empty-label* (getf results :value)) + (parser-start construct (getf results :query-string))) + (let* ((label-name + (trim-whitespace-right (string-until trimmed-string ":"))) + (next-query-str + (trim-whitespace-left (string-after trimmed-string ":"))) + (results (parse-bracket-value next-query-str construct))) + (add-prefix construct label-name (getf results :value)) + (parser-start construct (getf results :query-string))))))) + + +(defun parse-bracket-value(query-string query-object &key (open "<") (close ">")) + "A helper function that checks the value of a statement within + two brackets, i.e. <prefix-value>. A list of the + form (:query-string string :value string) is returned." + (declare (String query-string open close) + (SPARQL-Query query-object)) + (let ((trimmed-string (trim-whitespace-left query-string))) + (if (and (string-starts-with trimmed-string open) + (> (length (string-after trimmed-string close)) 0)) + (let* ((pref-url + (string-until (string-after trimmed-string open) close)) + (next-query-str + (string-after pref-url close))) + (unless next-query-str + (error (make-sparql-parser-condition + trimmed-string (original-query query-object) + close))) + (list :query-string next-query-str + :value pref-url)) + (error (make-sparql-parser-condition + trimmed-string (original-query query-object) + open))))) + + + +;((PREFIX bounding: <uri-prefix>)|(PREFIX : <uri-prefix>)* +;(BASE <base-uri>)*)* +;SELECT ?varName+ +;WHERE { +;(({?subjectOrVarName predicateOrVarName objectOrVarName}?)* +;({?FILTER (filterExpression)}?)* +;(BASE <base-uri>)*)* +;} +;Grouping +;{} +;Base +;BASE <uri> +;… +;<book> +;-> uri/book +;Literals +;(“anyCharacter*“)|(‘anyCharacter*‘)((anyUri)|(@languageTag)){0,1} +; +;Variables +;($anyChar*)|(?anyChar*) +;?var = $var +;Predicate object-lists +;?x foaf:name ?name ; +;foaf:mbox ?mbox . +;This is the same as writing the triple patterns: +;?x foaf:name ?name . +;?x foaf:mbox ?mbox . +;rdf:type +;rdf:type = a +;Empty Graph Pattern +;The group pattern: +;{ } +;matches any graph (including the empty graph) with one solution that does not bind any variables. For example: +;SELECT ?x +;WHERE {} +;matches with one solution in which variable x is not bound." \ No newline at end of file Modified: trunk/src/base-tools/base-tools.lisp ============================================================================== --- trunk/src/base-tools/base-tools.lisp (original) +++ trunk/src/base-tools/base-tools.lisp Wed Nov 17 16:41:59 2010 @@ -13,7 +13,14 @@ (:export :push-string :when-do :remove-null - :full-path)) + :full-path + :trim-whitespace-left + :trim-whitespace-right + :trim-whitespace + :string-starts-with + :string-starts-with-char + :string-until + :string-after)) (in-package :base-tools) @@ -52,4 +59,53 @@ (full-path-string "")) (dolist (segment segments) (push-string segment full-path-string)) - (concatenate 'string full-path-string "/" (pathname-name pathname)))) \ No newline at end of file + (concatenate 'string full-path-string "/" (pathname-name pathname)))) + + +(defun trim-whitespace-left (value) + "Uses string-left-trim with a predefined character-list." + (declare (String value)) + (string-left-trim '(#\Space #\Tab #\Newline) value)) + + +(defun trim-whitespace-right (value) + "Uses string-right-trim with a predefined character-list." + (declare (String value)) + (string-right-trim '(#\Space #\Tab #\Newline) value)) + + +(defun trim-whitespace (value) + "Uses string-trim with a predefined character-list." + (declare (String value)) + (string-trim '(#\Space #\Tab #\Newline) value)) + + +(defun string-starts-with (str prefix) + "Checks if string str starts with a given prefix." + (declare (string str prefix)) + (string= str prefix :start1 0 :end1 + (min (length prefix) + (length str)))) + + +(defun string-starts-with-char (begin str) + (equal (char str 0) begin)) + + +(defun string-until (str anchor) + "Returns a substring until the position of the passed anchor." + (declare (String str anchor)) + (let ((pos (search anchor str))) + (if pos + (subseq str 0 pos) + str))) + + +(defun string-after (str prefix) + "Returns the substring after the found prefix. + If there is no substring equal to prefix nil is returned." + (declare (String str prefix)) + (let ((pos (search prefix str))) + (if pos + (subseq str (+ pos (length prefix))) + nil))) \ No newline at end of file Modified: trunk/src/isidorus.asd ============================================================================== --- trunk/src/isidorus.asd (original) +++ trunk/src/isidorus.asd Wed Nov 17 16:41:59 2010 @@ -41,9 +41,9 @@ :depends-on ("exceptions"))) :depends-on ("constants" "base-tools")) (:module "TM-SPARQL" - :components ((:file "sparql" - :depends-on ("sparql_tokenizer")) - (:file "sparql_tokenizer")) + :components ((:file "sparql") + (:file "sparql_parser" + :depends-on ("sparql"))) :depends-on ("constants" "base-tools" "model")) (:module "xml" :components ((:module "xtm" Modified: trunk/src/model/datamodel.lisp ============================================================================== --- trunk/src/model/datamodel.lisp (original) +++ trunk/src/model/datamodel.lisp Wed Nov 17 16:41:59 2010 @@ -135,7 +135,6 @@ :list-instanceOf :list-super-types :in-topicmap - :string-starts-with :get-fragments :get-fragment :get-all-revisions @@ -884,14 +883,6 @@ (slot-value construct (find-symbol "OID" 'elephant))) -(defun string-starts-with (str prefix) - "Checks if string str starts with a given prefix." - (declare (string str prefix)) - (string= str prefix :start1 0 :end1 - (min (length prefix) - (length str)))) - - ;;; generic definitions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defgeneric mark-as-deleted (construct &key source-locator revision) (:documentation "Mark a construct as deleted if it comes from the source Modified: trunk/src/model/exceptions.lisp ============================================================================== --- trunk/src/model/exceptions.lisp (original) +++ trunk/src/model/exceptions.lisp Wed Nov 17 16:41:59 2010 @@ -17,10 +17,25 @@ :not-mergable-error :missing-argument-error :tm-reference-error - :bad-type-error)) + :bad-type-error + :missing-query-string-error + :sparql-parser-error)) (in-package :exceptions) + +(define-condition missing-query-string-error(error) + ((message + :initarg :message + :accessor message))) + + +(define-condition sparql-parser-error(error) + ((message + :initarg :message + :accessor message))) + + (define-condition inconsistent-file-error(error) ((message :initarg :message Modified: trunk/src/xml/rdf/exporter.lisp ============================================================================== --- trunk/src/xml/rdf/exporter.lisp (original) +++ trunk/src/xml/rdf/exporter.lisp Wed Nov 17 16:41:59 2010 @@ -8,7 +8,8 @@ ;;+----------------------------------------------------------------------------- (defpackage :rdf-exporter - (:use :cl :cxml :elephant :datamodel :isidorus-threading :datamodel) + (:use :cl :cxml :elephant :datamodel :isidorus-threading + :datamodel :base-tools) (:import-from :constants *rdf-ns* *rdfs-ns* Modified: trunk/src/xml/xtm/tools.lisp ============================================================================== --- trunk/src/xml/xtm/tools.lisp (original) +++ trunk/src/xml/xtm/tools.lisp Wed Nov 17 16:41:59 2010 @@ -275,15 +275,11 @@ (defun xpath-single-child-elem-by-qname (elem namespace-uri local-name) - "Returns some child of elem that has qname (namespace-uri local-name) or -nil if no such child exists." + "Returns some child of elem that has qname (namespace-uri local-name) + or nil if no such child exists." (declare (dom:element elem)) - (find-if (lambda (el) (has-qname el namespace-uri local-name)) (dom:child-nodes elem)) - ) - - -(defun string-starts-with (begin str) - (equal (char str 0) begin)) + (find-if (lambda (el) (has-qname el namespace-uri local-name)) + (dom:child-nodes elem))) (defun xpath-select-location-path (elem list-of-qnames) @@ -297,7 +293,7 @@ (cond (list-of-qnames (cond - ((string-starts-with #\@ local-name) + ((string-starts-with-char #\@ local-name) (list (dom:get-attribute-node-ns elem namespace-uri (string-left-trim "@" local-name)))) (t (apply #'append