Author: lgiessmann
Date: Thu Aug 27 05:10:55 2009
New Revision: 121
Log:
rdf-exporter: changed the handling of associations that were mapped from rdf->tm, thus currently the rdf-mapped associatons are exported directly as rdf-property within an rdf-resource-node. rdf:_n is transformed to rdf:li, therefor associations rdf-mapped-associations and occurrences that will be mapped as usual rdf-properties are sorted by there type-psi; note all unit tests has to be updated, since the exported dom has a different structure
Modified:
trunk/src/xml/rdf/exporter.lisp
Modified: trunk/src/xml/rdf/exporter.lisp
==============================================================================
--- trunk/src/xml/rdf/exporter.lisp (original)
+++ trunk/src/xml/rdf/exporter.lisp Thu Aug 27 05:10:55 2009
@@ -24,23 +24,54 @@
(:import-from :isidorus-threading
with-reader-lock
with-writer-lock)
- (:import-from :exporter
- *export-tm*
- export-to-elem)
(:export :export-rdf))
(in-package :rdf-exporter)
+(defvar *export-tm* nil "TopicMap which is exported (nil if all is
+ to be exported, the same mechanism as
+ in xtm-exporter")
+
(defvar *ns-map* nil) ;; ((:prefix <string> :uri <string>))
+(defun rdf-li-or-uri (uri)
+ "Returns a string which represents an URI. If the given URI is
+ of the type rdf:_n there will be returned rdf:li."
+ (let ((rdf-len (length *rdf-ns*)))
+ (let ((prep-uri (when (string-starts-with
+ uri (concatenate 'string *rdf-ns* "_"))
+ (subseq uri (+ rdf-len 1)))))
+ (if prep-uri
+ (handler-case (progn
+ (parse-integer prep-uri)
+ (concatenate 'string *rdf-ns* "li"))
+ (condition () uri))
+ uri))))
+
+
+(defun init-*ns-map* ()
+ "Initializes the variable *ns-map* woith some prefixes and corresponding
+ namepsaces. So the predifend namespaces are not contain ed twice."
+ (setf *ns-map* (list
+ (list :prefix "isi"
+ :uri *tm2rdf-ns*)
+ (list :prefix "rdf"
+ :uri *rdf-ns*)
+ (list :prefix "rdfs"
+ :uri *rdfs-ns*)
+ (list :prefix "xml"
+ :uri *xml-ns*))))
+
+
(defmacro with-property (construct &body body)
"Generates a property element with a corresponding namespace
and tag name before executing the body. This macro is for usin
in occurrences and association that are mapped to RDF properties."
`(let ((ns-list
- (separate-uri (uri (first (psis (instance-of ,construct)))))))
+ (separate-uri (rdf-li-or-uri
+ (uri (first (psis (instance-of ,construct))))))))
(declare ((or OccurrenceC AssociationC) ,construct))
(let ((ns (getf ns-list :prefix))
(tag-name (getf ns-list :suffix)))
@@ -50,12 +81,34 @@
,@body)))))
+(defmacro export-to-elem (tm to-elem)
+ "Exports all topics and associations depending to the given
+ tm. If tm is nil all topics and associations are exported.
+ Thic macro is equal to the one in xtm-exporter with a different
+ handler for associations."
+ `(setf *export-tm* ,tm)
+ `(format t "*export-tm*: ~a" *export-tm*)
+ `(map 'list
+ ,to-elem
+ (remove-if
+ #'null
+ (map 'list
+ #'(lambda(top)
+ (d:find-item-by-revision top revision))
+ (if ,tm
+ (union
+ (d:topics ,tm) (d:associations ,tm))
+ (union
+ (elephant:get-instances-by-class 'd:TopicC)
+ (list-tm-associations)))))))
+
+
(defun export-rdf (rdf-path &key tm-id (revision (get-revision)))
"Exports the topoic map bound to tm-id as RDF."
(with-reader-lock
(let ((tm (when tm-id
(get-item-by-item-identifier tm-id :revision revision))))
- (setf *ns-map* nil)
+ (init-*ns-map*)
(setf *export-tm* tm)
(with-revision revision
(with-open-file (stream rdf-path :direction :output)
@@ -288,7 +341,8 @@
(ii (item-identifiers construct))
(sl (locators construct))
(t-names (names construct))
- (t-occs (occurrences construct)))
+ (t-occs (occurrences construct))
+ (t-assocs (list-rdf-mapped-associations construct)))
(if psi
(cxml:attribute "rdf:about" (uri psi))
(cxml:attribute "rdf:nodeID" (make-object-id construct)))
@@ -308,7 +362,20 @@
(make-topic-reference x)))
(list-super-types construct))
(map 'list #'to-rdf-elem t-names)
- (map 'list #'to-rdf-elem t-occs)))))
+ (map 'list #'to-rdf-elem (sort-constructs
+ (union t-occs t-assocs)))))))
+
+
+(defun sort-constructs (constructs)
+ "Sorts names and associations by the instance-of name.
+ So rdf:_n can be exported in the correct order."
+ (sort constructs #'(lambda(x y)
+ (declare ((or OccurrenceC AssociationC) x y))
+ (let ((x-psi (when (psis (instance-of x))
+ (uri (first (psis (instance-of x))))))
+ (y-psi (when (psis (instance-of y))
+ (uri (first (psis (instance-of y)))))))
+ (string< x-psi y-psi)))))
(defmethod to-rdf-elem ((construct AssociationC))
@@ -387,12 +454,52 @@
association-roles)))
(when (and subject-role object-role
(= (length association-roles) 2))
- (cxml:with-element "rdf:Description"
- (let ((psi (when (psis (player subject-role))
- (first (psis (player subject-role))))))
- (if psi
- (cxml:attribute "rdf:about" (uri psi))
- (cxml:attribute "rdf:nodeID"
- (make-object-id (player subject-role))))
- (with-property association
- (make-topic-reference (player object-role)))))))))
\ No newline at end of file
+ (with-property association
+ (make-topic-reference (player object-role)))))))
+
+
+(defun list-rdf-mapped-associations(subject-topic)
+ "Returns all associations that were mapped from RDF to TM
+ and are still having two roles of the type isi:subject and
+ isi:object."
+ (declare (TopicC subject-topic))
+ (let ((isi-subject (get-item-by-psi *rdf2tm-subject*))
+ (isi-object (get-item-by-psi *rdf2tm-object*)))
+ (let ((topic-roles
+ (remove-if
+ #'null
+ (map 'list
+ #'(lambda(x)
+ (when (and (eql (instance-of x) isi-subject)
+ (= (length (roles (parent x))) 2)
+ (find-if #'(lambda(y)
+ (eql (instance-of y) isi-object))
+ (roles (parent x))))
+ x))
+ (player-in-roles subject-topic)))))
+ (map 'list #'parent topic-roles))))
+
+
+(defun list-tm-associations()
+ "Returns a list of associations that were not mapped from RDF
+ and are not of the type type-instance or supertype-subtype."
+ (let ((isi-subject (get-item-by-psi *rdf2tm-subject*))
+ (isi-object (get-item-by-psi *rdf2tm-object*))
+ (type-instance (get-item-by-psi *type-instance-psi*))
+ (supertype-subtype (get-item-by-psi *supertype-subtype-psi*)))
+ (remove-if
+ #'null
+ (map 'list
+ #'(lambda(x)
+ (when (and
+ (not (or (eql (instance-of x) type-instance)
+ (eql (instance-of x) supertype-subtype)))
+ (or (/= (length (roles x)) 2)
+ (not (find-if #'(lambda(y)
+ (eql (instance-of y) isi-object))
+ (roles x)))
+ (not (find-if #'(lambda(y)
+ (eql (instance-of y) isi-subject))
+ (roles x)))))
+ x))
+ (elephant:get-instances-by-class 'AssociationC)))))
\ No newline at end of file