As different bibtex types share common keys, it is advantageous to separate data extraction from json, and the formatting of the bibtex entry.
#+BEGIN_SRC emacs-lisp :tangle doi-utils.el
-(defmacro defpar (name &optional value)
- `(progn (defvar ,name)
- (setf ,name ,value)))
-
-(defpar doi-utils-json-metadata-extract
- '((type (plist-get results :type))
- (author (mapconcat (lambda (x) (concat (plist-get x :given) " " (plist-get x :family)))
- (plist-get results :author) " and "))
- (title (plist-get results :title))
- (subtitle (plist-get results :subtitle))
- (journal (plist-get results :container-title))
- (series (plist-get results :container-title))
- (publisher (plist-get results :publisher))
- (volume (plist-get results :volume))
- (issue (plist-get results :issue))
- (number (plist-get results :issue))
- (year (elt (elt (plist-get (plist-get results :issued) :date-parts) 0) 0))
- (month (elt (elt (plist-get (plist-get results :issued) :date-parts) 0) 1))
- (pages (plist-get results :page))
- (doi (plist-get results :DOI))
- (url (plist-get results :URL))
- (booktitle (plist-get results :container-title))))
+(setq doi-utils-json-metadata-extract
+ '((type (plist-get results :type))
+ (author (mapconcat (lambda (x) (concat (plist-get x :given) " " (plist-get x :family)))
+ (plist-get results :author) " and "))
+ (title (plist-get results :title))
+ (subtitle (plist-get results :subtitle))
+ (journal (plist-get results :container-title))
+ (series (plist-get results :container-title))
+ (publisher (plist-get results :publisher))
+ (volume (plist-get results :volume))
+ (issue (plist-get results :issue))
+ (number (plist-get results :issue))
+ (year (elt (elt (plist-get (plist-get results :issued) :date-parts) 0) 0))
+ (month (elt (elt (plist-get (plist-get results :issued) :date-parts) 0) 1))
+ (pages (plist-get results :page))
+ (doi (plist-get results :DOI))
+ (url (plist-get results :URL))
+ (booktitle (plist-get results :container-title))))
#+END_SRC
Next, we need to define the different bibtex types. Each type has a bibtex type (for output) and the type as provided in the doi record. Finally, we have to declare the fields we want to output.
#+BEGIN_SRC emacs-lisp :tangle doi-utils.el :results none
-(defpar doi-utils-bibtex-type-generators nil)
+(setq doi-utils-bibtex-type-generators nil)
-(defun concat-prepare (lst &optional acc)
+(defun doi-utils-concat-prepare (lst &optional acc)
"Given a list `lst' of strings and other expressions, which are
intented to passed to `concat', concat any subsequent strings,
minimising the number of arguments being passed to `concat'
(cond ((null lst) (nreverse acc))
((and (stringp (car lst))
(stringp (car acc)))
- (concat-prepare (cdr lst) (cons (concat (car acc) (car lst))
+ (doi-utils-concat-prepare (cdr lst) (cons (concat (car acc) (car lst))
(cdr acc))))
- (t (concat-prepare (cdr lst) (cons (car lst) acc)))))
-
+ (t (doi-utils-concat-prepare (cdr lst) (cons (car lst) acc)))))
(defmacro doi-utils-def-bibtex-type (name matching-types &rest fields)
"Define a BibTeX type identified by (symbol) `name' with
(error "unknown bibtex field type %s" field))))
fields)
(concat
- ,@(concat-prepare
+ ,@(doi-utils-concat-prepare
(-flatten
(list (concat "@" (symbol-name name) "{,\n")
;; there seems to be some bug with mapcan,
(doi-utils-def-bibtex-type book ("book")
author title series publisher year pages doi url)
+
+(doi-utils-def-bibtex-type inbook ("book-chapter")
+ author title booktitle series publisher year pages doi url)
+
#+END_SRC
With the code generating the bibtex entry in place, we can glue it to the json retrieval code.
#+BEGIN_SRC emacs-lisp :tangle doi-utils.el
(defun doi-utils-doi-to-bibtex-string (doi)
- "return a bibtex entry as a string for the doi. Only articles are currently supported"
+ "return a bibtex entry as a string for the doi. Not all types are supported yet."
(let* ((results (doi-utils-get-json-metadata doi))
(type (plist-get results :type)))
- (format "%s" results) ; json-data
+ ;(format "%s" results) ; json-data
(or (some (lambda (g) (funcall g type results)) doi-utils-bibtex-type-generators)
- (message-box "%s not supported yet." type))))
+ (message "%s not supported yet\n%S." type results))))
#+END_SRC
#+RESULTS:
(interactive "sDOI :")
(insert (doi-utils-doi-to-bibtex-string doi))
(backward-char)
+ ;; set date added for the record
+ (bibtex-set-field "DATE_ADDED" (current-time-string))
(if (bibtex-key-in-head nil)
(org-ref-clean-bibtex-entry t)
(org-ref-clean-bibtex-entry))
(doi-utils-get-bibtex-entry-pdf)
(save-selected-window
(org-ref-open-bibtex-notes)))
+
#+END_SRC
It may be you are in some other place when you want to add a bibtex entry. This next function will open the first entry in org-ref-default-bibliography go to the end, and add the entry. You can sort it later.
(insert value))))
#+END_SRC
-The updating function looks like this. We get all the keys from the json plist metadata, and update the fields if they exist.
+The updating function for a whole entry looks like this. We get all the keys from the json plist metadata, and update the fields if they exist.
#+BEGIN_SRC emacs-lisp :tangle doi-utils.el
(defun plist-get-keys (plist)
(org-ref-clean-bibtex-entry t)
(org-ref-clean-bibtex-entry)))
#+END_SRC
+
+A downside to updating an entry is it overwrites what you have already fixed. So, we next develop a function to update the field at point.
+
+#+BEGIN_SRC emacs-lisp
+(defun doi-utils-update-field ()
+ (interactive)
+ (let* ((doi (bibtex-autokey-get-field "doi"))
+ (results (doi-utils-get-json-metadata doi))
+ (field (car (bibtex-find-text-internal nil nil ","))))
+ (cond
+ ((string= field "volume")
+ (bibtex-set-field field (plist-get results :volume)))
+ ((string= field "number")
+ (bibtex-set-field field (plist-get results :issue)))
+ ((string= field "pages")
+ (bibtex-set-field field (plist-get results :page)))
+ ((string= field "year")
+ (bibtex-set-field field (plist-get results :year)))
+ (t
+ (message "%s not supported yet." field)))))
+#+END_SRC
+
+
* DOI functions for WOS
I came across this API http://wokinfo.com/media/pdf/OpenURL-guide.pdf to make links to the things I am interested in here. Based on that document, here are three links based on a doi:10.1021/jp047349j that take you to different Web Of Science (WOS) pages.
+* Debugging a DOI
+I wrote this function to help debug a DOI. This function generates an org-buffer with the doi, gets the json metadata, shows the bibtex entry, and the pdf link for it.
+
+#+BEGIN_SRC emacs-lisp :tangle doi-utils.el
+(defun doi-utils-debug (doi)
+ "Generate an org-buffer showing data about DOI."
+ (interactive "sDOI: ")
+ (switch-to-buffer "*debug-doi*")
+ (erase-buffer)
+ (org-mode)
+ (insert (concat "doi:" doi) "\n\n")
+ (insert "* JSON
+" (format "%s" (doi-utils-get-json-metadata doi)) "
+
+* Bibtex
+
+" (doi-utils-doi-to-bibtex-string doi) "
+
+* PDF
+" (doi-utils-get-pdf-url doi)))
+#+END_SRC
+
+#+RESULTS:
+: doi-utils-debug
+
* Adding a bibtex entry from a crossref query
The idea here is to perform a query on Crossref, get a helm buffer of candidates, and select the entry(ies) you want to add to your bibtex file. You can select a region, e.g. a free form citation, or set of words, or you can type the query in by hand.