~bzg/ox-skos

a6ba966b5021e6480b084ecfb2b30256eb6612db — Bastien 5 years ago 6fb2847
Significant refactoring

* ox-skos.el: Update comment section about new keywords.
(org-skos-uri-separator, org-skos-id-separator)
(org-skos-ISO-25964): New options.
(skos): Use new keywords.
(org-skos-i18n, org-skos-headline, org-skos-build-iso-thes-term)
(org-skos-build-iso-thes-terms)
(org-skos-build-top-level-description, org-skos-template):
Significant refactoring.  Use new keywords and options.
1 files changed, 115 insertions(+), 84 deletions(-)

M ox-skos.el
M ox-skos.el => ox-skos.el +115 -84
@@ 28,16 28,18 @@
;; This backend understands these new option keywords:
;;
;; #+SKOS_EXTENSION: rdf (the default)
;; #+SKOS_CONCEPTSCHEMEURI: set the base concept scheme URI.
;; #+CONCEPTSCHEMEID: set the ID of the concept scheme 
;; #+CONCEPTSCHEMEBASEURI: set the concept scheme base URI
;; #+CONCEPTSCHEMEID: set the concept scheme ID
;;
;;; Todo:
;;
;; - use :skos:note:fr: to specify the language
;; - use :skos:note:1 or :skos:note:note_label for multiple notes
;; - use :skos:note:fr: to specify the language?
;; - use :skos:note:1 or :skos:note:note_label for multiple notes?
;; - implement related (add var with list of properties?)
;; - use SKOS_EXTENSION for ttl output ?
;; - use SKOS_EXTENSION for ttl output?
;; - write ox-skos-html to export to html
;; - write ox-skos-latex to export to latex (anf scribble?!)
;; - write ox-skos-latex to export to latex (and scribble?!)

;;; Code:



@@ 59,6 61,29 @@
  :group 'org-export-skos
  :type 'string)

(defcustom org-skos-uri-separator "/"
  "Separate the concept scheme URI and the concept scheme ID."
  :group 'org-export-skos
  :type 'string)

(defcustom org-skos-id-separator "-"
  "Separate the concept scheme ID and the concept ID."
  :group 'org-export-skos
  :type 'string)

;; (setq org-skos-uri-separator "/")
;; (setq org-skos-id-separator "-")

(defcustom org-skos-ISO-25964 nil
  "When non-nil, include ISO-THES data."
  :group 'org-export-skos
  :type 'boolean)

;; (setq org-skos-ISO-25964 nil)

(defvar org-skos-terms nil
  "A list of terms to generate iso-thes data.")

;;; Define backend

(org-export-define-derived-backend 'skos 'html


@@ 78,7 103,8 @@
    (:publisher   "PUBLISHER" nil nil newline)
    (:subject     "SUBJECT" nil nil newline)
    (:keywords    "KEYWORDS" nil nil space)
    (:skos-conceptschemeuri "SKOS_CONCEPTSCHEMEURI" nil nil t)
    (:conceptschemebaseuri "CONCEPTSCHEMEBASEURI" nil nil t)
    (:conceptschemeid "CONCEPTSCHEMEID" nil nil t)
    (:with-toc nil nil nil)
    (:skos-extension "SKOS_EXTENSION" nil org-skos-extension))
  :filters-alist '((:filter-final-output . org-skos-final-function))


@@ 89,13 115,6 @@
		     (paragraph . (lambda (&rest args) ""))
		     (template . org-skos-template)))

;;; Export variables

(defvar org-skos-uri-separator "#")

(defvar org-skos-terms nil
  "A list of terms to generate iso-thes data.")

;;; Export functions

;;;###autoload


@@ 168,29 187,28 @@ Return output file name."

;;; Main transcoding functions

(defun org-skos-i18n (value lang attr conceptschemeuri)
(defun org-skos-i18n (value lang attr conceptschemeuri conceptschemebaseuri)
  "Convert VALUE with LANG into xml attribute ATTR.
VALUE can be a string or an alist."
  (if (null value) ""
    (let* ((values (org-babel-parse-header-arguments value))
	   (uuid (org-id-new))
	   (attr0 (when (string-match "[^:]+:\\(.+\\)" attr)
		    (match-string 1 attr)))
	   (iso-thes-attr
	    (cond ((string= attr0 "prefLabel") "PreferredTerm")
		  ((string= attr0 "altLabel") "SimpleNonPreferredTerm")
		  (t ""))))
    (let ((values (org-babel-parse-header-arguments value))
	  (id (org-id-new))
	  (attr0 (when (string-match "[^:]+:\\(.+\\)" attr)
			 (match-string 1 attr))))
      (concat
       (when (or (string= attr0 "prefLabel")
		 (string= attr0 "altLabel"))
       (when (and org-skos-ISO-25964
		  (or (string= attr0 "prefLabel")
		      (string= attr0 "altLabel")))
	 ;; Update the global list of terms
	 (push (list uuid attr0 values)
	       org-skos-terms)
	 (push (list id attr0 values) org-skos-terms)
	 (format (concat
		  "<xl:" attr0 ">\n<iso-thes:" iso-thes-attr
		  "<xl:" attr0 ">\n<iso-thes:"
		  (cond ((string= attr0 "prefLabel") "PreferredTerm")
			((string= attr0 "altLabel") "SimpleNonPreferredTerm")
			(t ""))
		  " rdf:about=\"%s" org-skos-uri-separator
		  "%s\" />\n</xl:" attr0 ">\n")
		 conceptschemeuri uuid))
		 conceptschemebaseuri id))
       (mapconcat
	(lambda (lv)
	  (let ((l (if (cdr lv) (substring (symbol-name (car lv)) 1) lang))


@@ 203,38 221,44 @@ VALUE can be a string or an alist."
  "Transcode HEADLINE element into SKOS format.
CONTENTS is the headline contents.  INFO is a plist used as a
communication channel."
  (let* ((uri (concat "#" 
		      (or (org-element-property :ID headline)
			  (url-encode-url
			   (org-element-property :URI headline)))))
  (let* ((id (or (org-element-property :ID headline)
		 (url-encode-url
		  (org-element-property :URI headline))))
	 (lang (org-export-data (plist-get info :language) info))
	 (timestr (format-time-string-ISO-8601))
	 ;; FIXME: check skos:scopeNote
	 (conceptschemebaseuri
	  (url-encode-url (plist-get info :conceptschemebaseuri)))
	 (conceptschemeuri
	  (url-encode-url (plist-get info :skos-conceptschemeuri)))
	  (concat
	   conceptschemebaseuri
	   org-skos-uri-separator
	   (url-encode-url (plist-get info :conceptschemeid))))
	 (notation
	  (org-skos-i18n
	   (org-element-property :SKOS:NOTATION headline)
	   lang "skos:notation" conceptschemeuri))
	   lang "skos:notation" conceptschemeuri conceptschemebaseuri))
	 (example
	  (org-skos-i18n
	   (org-element-property :SKOS:EXAMPLE headline)
	   lang "skos:example" conceptschemeuri))
	   lang "skos:example" conceptschemeuri conceptschemebaseuri))
	 (note
	  (org-skos-i18n
	   (org-element-property :SKOS:NOTE headline)
	   lang "skos:note" conceptschemeuri))
	   lang "skos:note" conceptschemeuri conceptschemebaseuri))
	 (altlabel
	  (org-skos-i18n
	   (org-element-property :SKOS:ALTLABEL headline)
	   lang "skos:altLabel" conceptschemeuri))
	   lang "skos:altLabel" conceptschemeuri conceptschemebaseuri))
	 (preflabel
	  (org-skos-i18n
	   (or (org-element-property :SKOS:PREFLABEL headline)
	       (org-element-property :raw-value headline))
	   lang "skos:prefLabel" conceptschemeuri))
	   lang "skos:prefLabel" conceptschemeuri conceptschemebaseuri))
	 (broader
	  (org-element-property :URI (org-export-get-parent-headline headline)))
	  (or
	   (org-element-property :ID (org-export-get-parent-headline headline))
	   (org-element-property :URI (org-export-get-parent-headline headline))))
	 (narrower  ;; a list of narrower URIs
	  (org-element-map (plist-get info :parse-tree) 'headline
	    (lambda (h)


@@ 242,7 266,9 @@ communication channel."
		   (org-element-property
		    :raw-value (org-export-get-parent-headline h))
		   (org-element-property :raw-value headline))
		  (org-element-property :URI h)))))
		  (or
		   (org-element-property :ID h)
		   (org-element-property :URI h))))))
	 (parent (org-element-property :parent headline))
	 ;; FIXME use org-export-get-previous-element?
	 (first-para


@@ 257,7 283,7 @@ communication channel."
	 (definition
	   (or (org-skos-i18n
		(org-element-property :SKOS:DEFINITION headline)
		lang "skos:definition" conceptschemeuri)
		lang "skos:definition" conceptschemeuri conceptschemebaseuri)
	       (and first-para
		    (format "<skos:definition xml:lang=\"%s\">%s</skos:definition>"
			    lang


@@ 269,45 295,44 @@ communication channel."
    (concat
     ;; Add basic SKOS info
     (format
      "<skos:Concept rdf:about=\"%s%s\">
      "<skos:Concept rdf:about=\"%s%s%s\">
  <rdf:type rdf:resource=\"http://www.w3.org/2004/02/skos/core#Concept\"/>
  <skos:inScheme>
    <skos:ConceptScheme rdf:about=\"%s\"/>
  </skos:inScheme>
<dct:modified>%s</dct:modified>
<dct:created>%s</dct:created>
  %s
  %s
  %s
  %s
  %s
  %s
<iso-thes:status>1</iso-thes:status>
"
      timestr timestr
      conceptschemeuri uri conceptschemeuri
      definition notation preflabel altlabel example note)
      conceptschemeuri org-skos-id-separator id
      conceptschemeuri
      timestr timestr)
     definition "\n" notation "\n" preflabel "\n"
     altlabel "\n" example "\n" note "\n"
     (when org-skos-ISO-25964 "<iso-thes:status>1</iso-thes:status>\n")
     ;; Possibly add "broader"
     (if broader
  	 (format "<skos:broader rdf:resource=\"%s%s\"/>\n" conceptschemeuri broader))
     (when broader
       (format "<skos:broader rdf:resource=\"%s%s\"/>\n" conceptschemeuri broader))
     ;; Possibly add "narrower"
     (if narrower
	 (mapconcat
	  (lambda (n)
	    (format "<skos:narrower rdf:resource=\"%s%s\"/>" conceptschemeuri n))
	  narrower "\n"))
     (when narrower
       (mapconcat
	(lambda (n)
	  (format "<skos:narrower rdf:resource=\"%s%s\"/>" conceptschemeuri n))
	narrower "\n"))
     ;; Possibly add topConceptOf
     (if (= (org-element-property :level headline) 1)
  	 (format "<skos:topConceptOf rdf:resource=\"%s\"/>" conceptschemeuri))
     (when (= (org-element-property :level headline) 1)
       (format "<skos:topConceptOf rdf:resource=\"%s\"/>" conceptschemeuri))
     ;; Possibly add iso-thes:status
     
     "\n</skos:Concept>\n"
     contents)))

(defun org-skos-build-iso-thes-term (term conceptschemeuri)
;; FIXME: id should be uuid, without the conceptscheme base URI
(defun org-skos-build-iso-thes-term (term conceptschemebaseuri)
  "Use `term' to build iso-thes bloc.
`term' is a list with a uuid, an iso-thes attribute and a list of
`term' is a list with an id, an iso-thes attribute and a list of
cons formed from a language specified and a litteral."
  (let ((timestr (format-time-string-ISO-8601))
	(uuid (car term))
	(id (car term))
	(attr (nth 1 term))
	(values (nth 2 term)))
    (format


@@ 318,7 343,7 @@ cons formed from a language specified and a litteral."
        <dct:created>%s</dct:created>
    </iso-thes:%s>"
     attr
     conceptschemeuri org-skos-uri-separator uuid
     conceptschemebaseuri org-skos-uri-separator id
     (mapconcat
      (lambda(v)
	(format "<xl:literalForm xml:lang=\"%s\">%s</xl:literalForm>"


@@ 331,10 356,10 @@ cons formed from a language specified and a litteral."

(defun org-skos-build-iso-thes-terms (contents info)
  "Build the list of iso-thes terms using `org-skos-terms'."
  (let ((conceptschemeuri (plist-get info :skos-conceptschemeuri)))
  (let ((conceptschemebaseuri (plist-get info :conceptschemebaseuri)))
    (mapconcat
     (lambda (term)
       (org-skos-build-iso-thes-term term conceptschemeuri))
       (org-skos-build-iso-thes-term term conceptschemebaseuri))
     org-skos-terms
     "\n")))



@@ 345,7 370,8 @@ cons formed from a language specified and a litteral."
    (format-time-string "%z"))))

(defun org-skos-build-top-level-description (contents info)
  (let ((conceptschemeuri (plist-get info :skos-conceptschemeuri))
  (let ((conceptschemebaseuri (plist-get info :conceptschemebaseuri))
	(conceptschemeid (plist-get info :conceptschemeid))
	(description (plist-get info :description))
	(lang (org-export-data (plist-get info :language) info))
	(title (org-export-data (plist-get info :title) info))


@@ 361,7 387,7 @@ cons formed from a language specified and a litteral."
	(coverage (org-export-data (plist-get info :coverage) info))
	(timestr (format-time-string-ISO-8601)))
    (concat
     (format "<skos:ConceptScheme rdf:about=\"%s\">
     (format "<skos:ConceptScheme rdf:about=\"%s%s%s\">
<rdf:type rdf:resource=\"http://www.w3.org/2004/02/skos/core#ConceptScheme\"/>
<dc:rights>%s</dc:rights>
<dct:created>%s</dct:created>


@@ 384,7 410,7 @@ cons formed from a language specified and a litteral."
</dc:creator>
<dct:description xml:lang=\"%s\">%s</dct:description>
<dct:title xml:lang=\"%s\">%s</dct:title>\n"
	     conceptschemeuri
	     conceptschemebaseuri org-skos-uri-separator conceptschemeid
	     rights
	     timestr
	     timestr


@@ 399,16 425,17 @@ cons formed from a language specified and a litteral."
	     lang description lang title)
     (mapconcat
      (lambda (uri)
	(format "<skos:hasTopConcept rdf:resource=\"%s%s\"/>"
		conceptschemeuri
	(format "<skos:hasTopConcept rdf:resource=\"%s%s%s%s%s\"/>"
		conceptschemebaseuri org-skos-uri-separator
		conceptschemeid org-skos-id-separator
		uri))
      (org-element-map (plist-get info :parse-tree)
	  'headline (lambda (h)
		      ;; Only consider top-level concepts
		      (if (= (org-element-property :level h) 1)
			  (concat "#" (or (org-element-property :ID h)
					  (url-encode-url
					   (org-element-property :URI h)))))))
			  (or (org-element-property :ID h)
			      (url-encode-url
			       (org-element-property :URI h))))))
      "\n")
     "\n</skos:ConceptScheme>")))



@@ 421,25 448,29 @@ as a communication channel."
	   (symbol-name org-html-coding-system))
   "<rdf:RDF
    xmlns:schema=\"http://schema.org/\"
    xmlns:owl=\"http://www.w3.org/2002/07/owl#\"
    xmlns:org=\"http://www.w3.org/ns/org#\"
    xmlns:xsd=\"http://www.w3.org/2001/XMLSchema#\"
    xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"
    xmlns:rdfs=\"http://www.w3.org/2000/01/rdf-schema#\"
    xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
    xmlns:dct=\"http://purl.org/dc/terms/\"
    xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"
    xmlns:prov=\"http://www.w3.org/ns/prov#\"
    xmlns:foaf=\"http://xmlns.com/foaf/0.1/\"
    xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
    xmlns:skos=\"http://www.w3.org/2004/02/skos/core#\"
    xmlns:skosxl=\"http://www.w3.org/2008/05/skos-xl#\"
    xmlns:euvoc=\"http://publications.europa.eu/ontology/euvoc#\">"
    xmlns:mcc=\"http://www.culture.fr/thesaurus/elements/1.0/\"
    xmlns:skos=\"http://www.w3.org/2004/02/skos/core#\""
   (if org-skos-ISO-25964
     "
    xmlns:xsd=\"http://www.w3.org/2001/XMLSchema#\"
    xmlns:euvoc=\"http://publications.europa.eu/ontology/euvoc#\"
    xmlns:prov=\"http://www.w3.org/ns/prov#\"
    xmlns:skosxl=\"http://www.w3.org/2008/05/skos-xl#\">"
     ">")
   "\n"
   "\n"
   ;; Add description of top-level concepts
   (org-skos-build-top-level-description contents info)
   "\n"
   contents
   (org-skos-build-iso-thes-terms contents info)
   (when org-skos-ISO-25964
     (org-skos-build-iso-thes-terms contents info))
   "\n</rdf:RDF>"))

(defun org-skos-section (section contents info)