X-Git-Url: https://cgit.sxemacs.org/?a=blobdiff_plain;f=lisp%2Fnnrss.el;h=55dd46067b07ec4dd8d08bd5658668bc750ff807;hb=9506fb26760bbd9fae1ecc8bc05627ceb847008c;hp=4eefba0a819f31492b12162fe4e43af8bbb889c3;hpb=0ff60821522a729920d2fb6e7703e209d171707c;p=gnus diff --git a/lisp/nnrss.el b/lisp/nnrss.el index 4eefba0a8..55dd46067 100644 --- a/lisp/nnrss.el +++ b/lisp/nnrss.el @@ -1,5 +1,5 @@ ;;; nnrss.el --- interfacing with RSS -;; Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. +;; Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. ;; Author: Shenghuo Zhu ;; Keywords: RSS @@ -54,7 +54,7 @@ (defvoo nnrss-group-max 0) (defvoo nnrss-group-min 1) (defvoo nnrss-group nil) -(defvoo nnrss-group-hashtb nil) +(defvoo nnrss-group-hashtb (make-hash-table :test 'equal)) (defvoo nnrss-status-string "") (defconst nnrss-version "nnrss 1.0") @@ -75,7 +75,7 @@ To use the description in headers, put this name into `nnmail-extra-headers'.") (defvar nnrss-content-function nil "A function which is called in `nnrss-request-article'. The arguments are (ENTRY GROUP ARTICLE). -ENTRY is the record of the current headline. GROUP is the group name. +ENTRY is the record of the current headline. GROUP is the group name. ARTICLE is the article number of the current headline.") (nnoo-define-basics nnrss) @@ -142,6 +142,7 @@ ARTICLE is the article number of the current headline.") (deffoo nnrss-request-article (article &optional group server buffer) (nnrss-possibly-change-group group server) (let ((e (assq article nnrss-group-data)) + (boundary "=-=-=-=-=-=-=-=-=-") (nntp-server-buffer (or buffer nntp-server-buffer)) post err) (when e @@ -149,7 +150,7 @@ ARTICLE is the article number of the current headline.") (with-current-buffer nntp-server-buffer (erase-buffer) (goto-char (point-min)) - (insert "Mime-Version: 1.0\nContent-Type: text/html\n") + (insert "Mime-Version: 1.0\nContent-Type: multipart/alternative; boundary=\"" boundary "\"\n") (if group (insert "Newsgroups: " group "\n")) (if (nth 3 e) @@ -160,19 +161,34 @@ ARTICLE is the article number of the current headline.") (insert "Date: " (nnrss-format-string (nth 5 e)) "\n")) (insert "Message-ID: " (format "<%d@%s.nnrss>" (car e) group) "\n") (insert "\n") - (if (nth 6 e) - (let ((point (point))) - (insert (nnrss-string-as-multibyte (nth 6 e))) + (let ((text (if (nth 6 e) + (nnrss-string-as-multibyte (nth 6 e)))) + (link (if (nth 2 e) + (nth 2 e)))) + (insert "\n\n--" boundary "\nContent-Type: text/plain\n\n") + (let ((point (point))) + (when text + (insert text) (goto-char point) (while (re-search-forward "\n" nil t) (replace-match " ")) (goto-char (point-max)) - (insert "\n\n") - (fill-region point (point)))) - (if (nth 2 e) - (insert "

link

\n")) - (if nnrss-content-function - (funcall nnrss-content-function e group article))))) + (insert "\n\n")) + (when link + (insert link))) + (insert "\n\n--" boundary "\nContent-Type: text/html\n\n") + (let ((point (point))) + (when text + (insert "\n" text "\n") + (goto-char point) + (while (re-search-forward "\n" nil t) + (replace-match " ")) + (goto-char (point-max)) + (insert "\n\n")) + (when link + (insert "

link

\n")))) + (when nnrss-content-function + (funcall nnrss-content-function e group article))))) (cond (err (nnheader-report 'nnrss err)) @@ -216,14 +232,8 @@ ARTICLE is the article number of the current headline.") (setq nnrss-server-data (delq (assoc group nnrss-server-data) nnrss-server-data)) (nnrss-save-server-data server) - (let ((file (expand-file-name - (nnrss-translate-file-chars - (concat group (and server - (not (equal server "")) - "-") - server ".el")) nnrss-directory))) - (ignore-errors - (delete-file file))) + (ignore-errors + (delete-file (nnrss-make-filename group server))) t) (deffoo nnrss-request-list-newsgroups (&optional server) @@ -241,33 +251,33 @@ ARTICLE is the article number of the current headline.") ;;; Internal functions (eval-when-compile (defun xml-rpc-method-call (&rest args))) (defun nnrss-fetch (url &optional local) - "Fetch the url and put it in a the expected lisp structure." + "Fetch URL and put it in a the expected Lisp structure." (with-temp-buffer - ;some CVS versions of url.el need this to close the connection quickly - (let* (xmlform htmlform) + ;;some CVS versions of url.el need this to close the connection quickly + (let (xmlform htmlform) ;; bit o' work necessary for w3 pre-cvs and post-cvs (if local (let ((coding-system-for-read 'binary)) (insert-file-contents url)) (mm-url-insert url)) -;; Because xml-parse-region can't deal with anything that isn't -;; xml and w3-parse-buffer can't deal with some xml, we have to -;; parse with xml-parse-region first and, if that fails, parse -;; with w3-parse-buffer. Yuck. Eventually, someone should find out -;; why w3-parse-buffer fails to parse some well-formed xml and -;; fix it. - - (condition-case err - (setq xmlform (xml-parse-region (point-min) (point-max))) - (error (if (fboundp 'w3-parse-buffer) - (setq htmlform (caddar (w3-parse-buffer - (current-buffer)))) - (message "nnrss: Not valid XML and w3 parse not available (%s)" - url)))) - (if htmlform - htmlform - xmlform)))) + ;; Because xml-parse-region can't deal with anything that isn't + ;; xml and w3-parse-buffer can't deal with some xml, we have to + ;; parse with xml-parse-region first and, if that fails, parse + ;; with w3-parse-buffer. Yuck. Eventually, someone should find out + ;; why w3-parse-buffer fails to parse some well-formed xml and + ;; fix it. + + (condition-case err + (setq xmlform (xml-parse-region (point-min) (point-max))) + (error (if (fboundp 'w3-parse-buffer) + (setq htmlform (caddar (w3-parse-buffer + (current-buffer)))) + (message "nnrss: Not valid XML and w3 parse not available (%s)" + url)))) + (if htmlform + htmlform + xmlform)))) (defun nnrss-possibly-change-group (&optional group server) (when (and server @@ -280,7 +290,7 @@ ARTICLE is the article number of the current headline.") (defvar nnrss-extra-categories '(nnrss-snarf-moreover-categories)) (defun nnrss-generate-active () - (if (y-or-n-p "fetch extra categories? ") + (if (y-or-n-p "Fetch extra categories? ") (dolist (func nnrss-extra-categories) (funcall func))) (save-excursion @@ -296,85 +306,62 @@ ARTICLE is the article number of the current headline.") (defun nnrss-read-server-data (server) (setq nnrss-server-data nil) - (let ((file (expand-file-name - (nnrss-translate-file-chars - (concat "nnrss" (and server - (not (equal server "")) - "-") - server - ".el")) - nnrss-directory))) + (let ((file (nnrss-make-filename "nnrss" server))) (when (file-exists-p file) - (with-temp-buffer - (let ((coding-system-for-read 'binary) - emacs-lisp-mode-hook) - (insert-file-contents file) - (emacs-lisp-mode) - (goto-char (point-min)) - (eval-buffer)))))) + (let ((coding-system-for-read 'binary)) + (load file nil nil t))))) (defun nnrss-save-server-data (server) (gnus-make-directory nnrss-directory) - (let ((file (expand-file-name - (nnrss-translate-file-chars - (concat "nnrss" (and server - (not (equal server "")) - "-") - server ".el")) - nnrss-directory))) - (let ((coding-system-for-write 'binary) - print-level print-length) - (with-temp-file file - (insert "(setq nnrss-group-alist '" - (prin1-to-string nnrss-group-alist) - ")\n") - (insert "(setq nnrss-server-data '" - (prin1-to-string nnrss-server-data) - ")\n"))))) + (let ((coding-system-for-write 'binary)) + (with-temp-file (nnrss-make-filename "nnrss" server) + (gnus-prin1 `(setq nnrss-group-alist ',nnrss-group-alist)) + (gnus-prin1 `(setq nnrss-server-data ',nnrss-server-data))))) (defun nnrss-read-group-data (group server) (setq nnrss-group-data nil) - (setq nnrss-group-hashtb (gnus-make-hashtable)) + (if (hash-table-p nnrss-group-hashtb) + (clrhash nnrss-group-hashtb) + (setq nnrss-group-hashtb (make-hash-table :test 'equal))) (let ((pair (assoc group nnrss-server-data))) (setq nnrss-group-max (or (cadr pair) 0)) (setq nnrss-group-min (+ nnrss-group-max 1))) - (let ((file (expand-file-name - (nnrss-translate-file-chars - (concat group (and server - (not (equal server "")) - "-") - server ".el")) - nnrss-directory))) + (let ((file (nnrss-make-filename group server))) (when (file-exists-p file) - (with-temp-buffer - (let ((coding-system-for-read 'binary) - emacs-lisp-mode-hook) - (insert-file-contents file) - (emacs-lisp-mode) - (goto-char (point-min)) - (eval-buffer))) + (let ((coding-system-for-read 'binary)) + (load file nil t t)) (dolist (e nnrss-group-data) - (gnus-sethash (nth 2 e) e nnrss-group-hashtb) - (if (and (car e) (> nnrss-group-min (car e))) - (setq nnrss-group-min (car e))) - (if (and (car e) (< nnrss-group-max (car e))) - (setq nnrss-group-max (car e))))))) + (puthash (or (nth 2 e) (nth 5 e)) t nnrss-group-hashtb) + (when (and (car e) (> nnrss-group-min (car e))) + (setq nnrss-group-min (car e))) + (when (and (car e) (< nnrss-group-max (car e))) + (setq nnrss-group-max (car e))))))) (defun nnrss-save-group-data (group server) (gnus-make-directory nnrss-directory) - (let ((file (expand-file-name - (nnrss-translate-file-chars - (concat group (and server - (not (equal server "")) - "-") - server ".el")) - nnrss-directory))) - (let ((coding-system-for-write 'binary) - print-level print-length) - (with-temp-file file - (insert "(setq nnrss-group-data '" - (prin1-to-string nnrss-group-data) - ")\n"))))) + (let ((coding-system-for-write 'binary)) + (with-temp-file (nnrss-make-filename group server) + (gnus-prin1 `(setq nnrss-group-data ',nnrss-group-data))))) + +(defun nnrss-make-filename (name server) + (expand-file-name + (nnrss-translate-file-chars + (concat name + (and server + (not (equal server "")) + "-") + server + ".el")) + nnrss-directory)) + +(gnus-add-shutdown 'nnrss-close 'gnus) + +(defun nnrss-close () + "Clear internal nnrss variables." + (setq nnrss-group-data nil + nnrss-server-data nil + nnrss-group-hashtb nil + nnrss-group-alist nil)) ;;; URL interface @@ -401,18 +388,23 @@ ARTICLE is the article number of the current headline.") ;;; Snarf functions (defun nnrss-check-group (group server) - (let (file xml subject url extra changed author date rss-ns rdf-ns content-ns dc-ns) + (let (file xml subject url extra changed author + date rss-ns rdf-ns content-ns dc-ns) (if (and nnrss-use-local (file-exists-p (setq file (expand-file-name (nnrss-translate-file-chars (concat group ".xml")) nnrss-directory)))) - (nnrss-fetch file t) + (setq xml (nnrss-fetch file t)) (setq url (or (nth 2 (assoc group nnrss-server-data)) (second (assoc group nnrss-group-alist)))) (unless url (setq url - (nnrss-discover-feed (read-string (format "URL to search for %s: " group) "http://"))) + (cdr + (assoc 'href + (nnrss-discover-feed + (read-string + (format "URL to search for %s: " group) "http://"))))) (let ((pair (assoc group nnrss-server-data))) (if pair (setcdr (cdr pair) (list url)) @@ -428,15 +420,20 @@ ARTICLE is the article number of the current headline.") content-ns (nnrss-get-namespace-prefix xml "http://purl.org/rss/1.0/modules/content/")) (dolist (item (nreverse (nnrss-find-el (intern (concat rss-ns "item")) xml))) (when (and (listp item) - (eq (intern (concat rss-ns "item")) (car item)) - (setq url (nnrss-decode-entities-unibyte-string - (nnrss-node-text rss-ns 'link (cddr item)))) - (not (gnus-gethash url nnrss-group-hashtb))) + (string= (concat rss-ns "item") (car item)) + (if (setq url (nnrss-decode-entities-unibyte-string + (nnrss-node-text rss-ns 'link (cddr item)))) + (not (gethash url nnrss-group-hashtb)) + (setq extra (or (nnrss-node-text content-ns 'encoded item) + (nnrss-node-text rss-ns 'description item))) + (not (gethash extra nnrss-group-hashtb)))) (setq subject (nnrss-node-text rss-ns 'title item)) - (setq extra (or (nnrss-node-text content-ns 'encoded item) + (setq extra (or extra + (nnrss-node-text content-ns 'encoded item) (nnrss-node-text rss-ns 'description item))) (setq author (or (nnrss-node-text rss-ns 'author item) - (nnrss-node-text dc-ns 'creator item))) + (nnrss-node-text dc-ns 'creator item) + (nnrss-node-text dc-ns 'contributor item))) (setq date (or (nnrss-node-text dc-ns 'date item) (nnrss-node-text rss-ns 'pubDate item) (message-make-date))) @@ -450,8 +447,9 @@ ARTICLE is the article number of the current headline.") date (and extra (nnrss-decode-entities-unibyte-string extra))) nnrss-group-data) - (gnus-sethash url (car nnrss-group-data) nnrss-group-hashtb) - (setq changed t))) + (puthash (or url extra) t nnrss-group-hashtb) + (setq changed t)) + (setq extra nil)) (when changed (nnrss-save-group-data group server) (let ((pair (assoc group nnrss-server-data))) @@ -460,6 +458,49 @@ ARTICLE is the article number of the current headline.") (push (list group nnrss-group-max) nnrss-server-data))) (nnrss-save-server-data server)))) +(defun nnrss-opml-import (opml-file) + "OPML subscriptions import. +Read the file and attempt to subscribe to each Feed in the file." + (interactive "fImport file: ") + (mapcar + (lambda (node) (gnus-group-make-rss-group + (cdr (assq 'xmlUrl (cadr node))))) + (nnrss-find-el 'outline + (progn + (find-file opml-file) + (xml-parse-region (point-min) + (point-max)))))) + +(defun nnrss-opml-export () + "OPML subscription export. +Export subscriptions to a buffer in OPML Format." + (interactive) + (with-current-buffer (get-buffer-create "*OPML Export*") + (mm-set-buffer-file-coding-system 'utf-8) + (insert (concat + "\n" + "\n" + "\n" + " \n" + " mySubscriptions\n" + " " (format-time-string "%a, %d %b %Y %T %z") + "\n" + " " user-mail-address "\n" + " " (user-full-name) "\n" + " \n" + " \n")) + (mapc (lambda (sub) + (insert (concat + " \n"))) + nnrss-group-alist) + (insert (concat + " \n" + "\n"))) + (pop-to-buffer "*OPML Export*") + (when (fboundp 'sgml-mode) + (sgml-mode))) + (defun nnrss-generate-download-script () "Generate a download script in the current buffer. It is useful when `(setq nnrss-use-local t)'." @@ -510,15 +551,13 @@ It is useful when `(setq nnrss-use-local t)'." (gnus-replace-in-string (nnrss-string-as-multibyte string) " *\n *" " ")) (defun nnrss-node-text (namespace local-name element) - (let* ((node (assq (intern (concat namespace (symbol-name local-name))) element)) + (let* ((node (assq (intern (concat namespace (symbol-name local-name))) + element)) (text (if (and node (listp node)) (nnrss-node-just-text node) node)) - (cleaned-text (if text - (replace-regexp-in-string - " *$" "" (replace-regexp-in-string - "^ *" "" (replace-regexp-in-string - "^[[:cntrl:]]+" "" text)))))) + (cleaned-text (if text (gnus-replace-in-string + text "^[\000-\037\177]+\\|^ +\\| +$" "")))) (if (string-equal "" cleaned-text) nil cleaned-text))) @@ -529,51 +568,52 @@ It is useful when `(setq nnrss-use-local t)'." node)) (defun nnrss-find-el (tag data &optional found-list) - "Find the all matching elements in the data. Careful with this on -large documents!" - (if (listp data) - (mapcar (lambda (bit) - (if (car-safe bit) - (progn (if (equal tag (car bit)) - (setq found-list - (append found-list - (list bit)))) - (if (and (listp (car-safe (caddr bit))) - (not (stringp (caddr bit)))) - (setq found-list - (append found-list - (nnrss-find-el - tag (caddr bit)))) - (setq found-list - (append found-list - (nnrss-find-el - tag (cddr bit)))))))) - data)) + "Find the all matching elements in the data. +Careful with this on large documents!" + (when (listp data) + (mapc (lambda (bit) + (when (car-safe bit) + (when (equal tag (car bit)) + (setq found-list + (append found-list + (list bit)))) + (if (and (listp (car-safe (caddr bit))) + (not (stringp (caddr bit)))) + (setq found-list + (append found-list + (nnrss-find-el + tag (caddr bit)))) + (setq found-list + (append found-list + (nnrss-find-el + tag (cddr bit))))))) + data)) found-list) (defun nnrss-rsslink-p (el) "Test if the element we are handed is an RSS autodiscovery link." (and (eq (car-safe el) 'link) (string-equal (cdr (assoc 'rel (cadr el))) "alternate") - (or (string-equal (cdr (assoc 'type (cadr el))) + (or (string-equal (cdr (assoc 'type (cadr el))) "application/rss+xml") (string-equal (cdr (assoc 'type (cadr el))) "text/xml")))) (defun nnrss-get-rsslinks (data) "Extract the elements that are links to RSS from the parsed data." - (delq nil (mapcar + (delq nil (mapcar (lambda (el) (if (nnrss-rsslink-p el) el)) (nnrss-find-el 'link data)))) (defun nnrss-extract-hrefs (data) - "Recursively extract hrefs from a page's source. DATA should be -the output of xml-parse-region or w3-parse-buffer." + "Recursively extract hrefs from a page's source. +DATA should be the output of `xml-parse-region' or +`w3-parse-buffer'." (mapcar (lambda (ahref) (cdr (assoc 'href (cadr ahref)))) (nnrss-find-el 'a data))) -(defmacro nnrss-match-macro (base-uri item +(defmacro nnrss-match-macro (base-uri item onsite-list offsite-list) `(cond ((or (string-match (concat "^" ,base-uri) ,item) (not (string-match "://" ,item))) @@ -594,28 +634,28 @@ whether they are `offsite' or `onsite'." rss-onsite-in rdf-onsite-in xml-onsite-in rss-offsite-end rdf-offsite-end xml-offsite-end rss-offsite-in rdf-offsite-in xml-offsite-in) - (mapcar (lambda (href) - (if (not (null href)) - (cond ((string-match "\\.rss$" href) - (nnrss-match-macro - base-uri href rss-onsite-end rss-offsite-end)) - ((string-match "\\.rdf$" href) - (nnrss-match-macro - base-uri href rdf-onsite-end rdf-offsite-end)) - ((string-match "\\.xml$" href) - (nnrss-match-macro - base-uri href xml-onsite-end xml-offsite-end)) - ((string-match "rss" href) - (nnrss-match-macro - base-uri href rss-onsite-in rss-offsite-in)) - ((string-match "rdf" href) - (nnrss-match-macro - base-uri href rdf-onsite-in rdf-offsite-in)) - ((string-match "xml" href) - (nnrss-match-macro - base-uri href xml-onsite-in xml-offsite-in))))) - hrefs) - (append + (mapc (lambda (href) + (if (not (null href)) + (cond ((string-match "\\.rss$" href) + (nnrss-match-macro + base-uri href rss-onsite-end rss-offsite-end)) + ((string-match "\\.rdf$" href) + (nnrss-match-macro + base-uri href rdf-onsite-end rdf-offsite-end)) + ((string-match "\\.xml$" href) + (nnrss-match-macro + base-uri href xml-onsite-end xml-offsite-end)) + ((string-match "rss" href) + (nnrss-match-macro + base-uri href rss-onsite-in rss-offsite-in)) + ((string-match "rdf" href) + (nnrss-match-macro + base-uri href rdf-onsite-in rdf-offsite-in)) + ((string-match "xml" href) + (nnrss-match-macro + base-uri href xml-onsite-in xml-offsite-in))))) + hrefs) + (append rss-onsite-end rdf-onsite-end xml-onsite-end rss-onsite-in rdf-onsite-in xml-onsite-in rss-offsite-end rdf-offsite-end xml-offsite-end @@ -648,7 +688,7 @@ whether they are `offsite' or `onsite'." ;; - offsite links containing any of the above (let* ((base-uri (progn (string-match ".*://[^/]+/?" url) (match-string 0 url))) - (hrefs (nnrss-order-hrefs + (hrefs (nnrss-order-hrefs base-uri (nnrss-extract-hrefs parsed-page))) (rss-link nil)) (while (and (eq rss-link nil) (not (eq hrefs nil))) @@ -664,53 +704,55 @@ whether they are `offsite' or `onsite'." (nnrss-find-rss-via-syndic8 url)))))))) (defun nnrss-find-rss-via-syndic8 (url) - "query syndic8 for the rss feeds it has for the url." - (condition-case nil - (progn (require 'xml-rpc) - (let ((feedid (xml-rpc-method-call - "http://www.syndic8.com/xmlrpc.php" - 'syndic8.FindSites - url))) - (if feedid - (let* ((feedinfo (xml-rpc-method-call - "http://www.syndic8.com/xmlrpc.php" - 'syndic8.GetFeedInfo - feedid)) - (urllist - (delq nil - (mapcar - (lambda (listinfo) - (if (string-equal - (cdr (assoc "status" listinfo)) - "Syndicated") - (cons - (cdr (assoc "sitename" listinfo)) - (list - (cons 'title - (cdr (assoc - "sitename" listinfo))) - (cons 'href - (cdr (assoc - "dataurl" listinfo))))))) - feedinfo)))) - (if (> (length urllist) 1) - (let ((completion-ignore-case t) - (selection - (mapcar (lambda (listinfo) - (cons (cdr (assoc "sitename" listinfo)) - (string-to-int - (cdr (assoc "feedid" listinfo))))) - feedinfo))) - (cdr (assoc - (completing-read - "Multiple feeds found. Select one: " - selection nil t) urllist))) - (cdar urllist)))))) - (message "XML-RPC is not available... not checking Syndic8."))) + "Query syndic8 for the rss feeds it has for URL." + (if (not (locate-library "xml-rpc")) + (progn + (message "XML-RPC is not available... not checking Syndic8.") + nil) + (require 'xml-rpc) + (let ((feedid (xml-rpc-method-call + "http://www.syndic8.com/xmlrpc.php" + 'syndic8.FindSites + url))) + (when feedid + (let* ((feedinfo (xml-rpc-method-call + "http://www.syndic8.com/xmlrpc.php" + 'syndic8.GetFeedInfo + feedid)) + (urllist + (delq nil + (mapcar + (lambda (listinfo) + (if (string-equal + (cdr (assoc "status" listinfo)) + "Syndicated") + (cons + (cdr (assoc "sitename" listinfo)) + (list + (cons 'title + (cdr (assoc + "sitename" listinfo))) + (cons 'href + (cdr (assoc + "dataurl" listinfo))))))) + feedinfo)))) + (if (not (> (length urllist) 1)) + (cdar urllist) + (let ((completion-ignore-case t) + (selection + (mapcar (lambda (listinfo) + (cons (cdr (assoc "sitename" listinfo)) + (string-to-int + (cdr (assoc "feedid" listinfo))))) + feedinfo))) + (cdr (assoc + (completing-read + "Multiple feeds found. Select one: " + selection nil t) urllist))))))))) (defun nnrss-rss-p (data) - "Test if data is an RSS feed. Simply ensures that the first -element is rss or rdf." + "Test if DATA is an RSS feed. +Simply ensures that the first element is rss or rdf." (or (eq (caar data) 'rss) (eq (caar data) 'rdf:RDF))) @@ -731,13 +773,13 @@ element is rss or rdf." that gives the URI for which you want to retrieve the namespace prefix), return the prefix." (let* ((prefix (car (rassoc uri (cadar el)))) - (nslist (if prefix + (nslist (if prefix (split-string (symbol-name prefix) ":"))) (ns (cond ((eq (length nslist) 1) ; no prefix given "") ((eq (length nslist) 2) ; extract prefix (cadr nslist))))) - (if (and ns (not (eq ns ""))) + (if (and ns (not (string= ns ""))) (concat ns ":") ns)))