Converting a doi to a bibtex entry
Posted May 22, 2014 at 04:22 PM | categories: bibtex | tags:
Many citation management packages allow you to download a bibliography entry from a doi. I want to be able to do that in emacs. I found this page that shows it is possible to get metadata about a doi with an http request, and from that data, we can create a bibtex entry. So, here is the basic code for getting metadata about a doi. We specify that we want json code, and then use json.el to view the results.
We temporarily set a few url-* variables with affect the url-retrieve results. And we rely on url-http-end-of-headers which tells us the end of the headers that get returned, so we can use the remaining text as the data.
(require 'json) (let ((url-request-method "GET") (url-mime-accept-string "application/citeproc+json") (json-object-type 'plist) (results)) (setq results (with-current-buffer (url-retrieve-synchronously "https://doi.org/10.1016/S0022-0248(97)00279-0") (json-read-from-string (buffer-substring url-http-end-of-headers (point-max))))))
(:volume 181 :indexed (:timestamp 1389218884442 :date-parts 2014 1 8) :publisher Elsevier BV :source CrossRef :URL https://doi.org/10.1016/S0022-0248(97) 00279-0 :ISSN [0022-0248] :DOI 10.1016/s0022-0248(97)00279-0 :type journal-article :title Effect of growth conditions on formation of TiO2-II thin films in atomic layer deposition process :issue 3 :deposited (:timestamp 1386028800000 :date-parts 2013 12 3) :page 259-264 :reference-count nil :container-title Journal of Crystal Growth :author [(:given Jaan :family Aarik) (:given Aleks :family Aidla) (:given Väino :family Sammelselg) (:given Teet :family Uustare)] :prefix http://id.crossref.org/prefix/10.1016 :score 1.0 :issued (:date-parts 1997 11) :subject [Condensed Matter Physics Inorganic Chemistry Materials Chemistry] :subtitle [])
That data is now sufficient for us to consider constructing a bibtex entry. For an article, a prototypical entry looks like:
@Article{, author = {}, title = {}, journal = {}, year = {}, OPTkey = {}, OPTvolume = {}, OPTnumber = {}, OPTpages = {}, OPTmonth = {}, OPTnote = {}, OPTannote = {} }
Let us create a function that takes a doi and constructs a bibtex entry. I do not use all the metadata, so I just store the json data in the annote field. Maybe I should use another field for that, but annote seems ok since I do not use if for anything. I am going to use a template expansion function I developed earlier to make the bibtex entry template easier to write and read. Here is the code.
(require 'json) (defun expand-template (s) "expand a template containing %{} with the eval of its contents" (replace-regexp-in-string "%{\\([^}]+\\)}" (lambda (arg) (let ((sexp (substring arg 2 -1))) (format "%s" (eval (read sexp))))) s)) (defun doi-to-bibtex-article (doi) "insert a bibtex entry for doi at point" (interactive "sDOI: ") (let ((url-request-method "GET") (url-mime-accept-string "application/citeproc+json") (json-object-type 'plist) type results author title journal year volume number pages month url json-data) (setq results (with-current-buffer (url-retrieve-synchronously (concat "https://doi.org/" doi)) (json-read-from-string (buffer-substring url-http-end-of-headers (point-max)))) 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) journal (plist-get results :container-title) volume (plist-get results :volume) issue (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) json-data (format "%s" results)) (when (string= type "journal-article") (expand-template "@article{, author = {%{author}}, title = {%{title}}, journal = {%{journal}}, year = {%{year}}, volume = {%{volume}}, number = {%{issue}}, pages = {%{pages}}, doi = {%{doi}}, url = {%{url}}, month = {%{month}}, json = {%{json-data}} }")))) (doi-to-bibtex-article "10.1016/s0022-0248(97)00279-0")
@article{, author = {Jaan Aarik and Aleks Aidla and Väino Sammelselg and Teet Uustare}, title = {Effect of growth conditions on formation of TiO2-II thin films in atomic layer deposition process}, journal = {Journal of Crystal Growth}, year = {1997}, volume = {181}, number = {3}, pages = {259-264}, doi = {10.1016/s0022-0248(97)00279-0}, url = {https://doi.org/10.1016/s0022-0248(97)00279-0}, month = {11}, json = {(:volume 181 :indexed (:timestamp 1389218884442 :date-parts [[2014 1 8]]) :publisher Elsevier BV :source CrossRef :URL https://doi.org/10.1016/s0022-0248(97)00279-0 :ISSN [0022-0248] :DOI 10.1016/s0022-0248(97)00279-0 :type journal-article :title Effect of growth conditions on formation of TiO2-II thin films in atomic layer deposition process :issue 3 :deposited (:timestamp 1386028800000 :date-parts [[2013 12 3]]) :page 259-264 :reference-count nil :container-title Journal of Crystal Growth :author [(:given Jaan :family Aarik) (:given Aleks :family Aidla) (:given Väino :family Sammelselg) (:given Teet :family Uustare)] :prefix http://id.crossref.org/prefix/10.1016 :score 1.0 :issued (:date-parts [[1997 11]]) :subject [Condensed Matter Physics Inorganic Chemistry Materials Chemistry] :subtitle [])} }
That looks excellent. Note there are some non-ascii characters in it, which would have to be fixed. Let us try it on an ASAP article.
(doi-to-bibtex-article "10.1021/ie403744u")
@article{, author = {José A. Delgado and V. I. Águeda and M. A. Uguina and J. L. Sotelo and P. Brea and Carlos A. Grande}, title = { Adsorption and Diffusion of H 2 , CO, CH 4 , and CO 2 in BPL Activated Carbon and 13X Zeolite: Evaluation of Performance in Pressure Swing Adsorption Hydrogen Purification by Simulation }, journal = {Industrial & Engineering Chemistry Research}, year = {2014}, volume = {nil}, number = {nil}, pages = {140117091024005}, doi = {10.1021/ie403744u}, url = {https://doi.org/10.1021/ie403744u}, month = {1}, json = {(:indexed (:timestamp 1392935578089 :date-parts [[2014 2 20]]) :publisher American Chemical Society (ACS) :source CrossRef :URL https://doi.org/10.1021/ie403744u :ISSN [0888-5885 1520-5045] :DOI 10.1021/ie403744u :type journal-article :title Adsorption and Diffusion of H 2 , CO, CH 4 , and CO 2 in BPL Activated Carbon and 13X Zeolite: Evaluation of Performance in Pressure Swing Adsorption Hydrogen Purification by Simulation :deposited (:timestamp 1389916800000 :date-parts [[2014 1 17]]) :page 140117091024005 :reference-count nil :container-title Industrial & Engineering Chemistry Research :author [(:given José A. :family Delgado) (:given V. I. :family Águeda) (:given M. A. :family Uguina) (:given J. L. :family Sotelo) (:given P. :family Brea) (:given Carlos A. :family Grande)] :prefix http://id.crossref.org/prefix/10.1021 :score 1.0 :issued (:date-parts [[2014 1 17]]) :subject [Chemistry(all) Industrial and Manufacturing Engineering Chemical Engineering(all)] :subtitle [])} }
You see that nil is put in for missing entries. That is probably ok. There is an & in the journal that needs to be cleaned up, but that is easily done with org-ref-clean-bibtex-entry. In summary, this looks like a very convenient way to get bibtex entries inside emacs. I should probably have the function insert that string to a buffer at point, but that is not difficult to do.
Copyright (C) 2014 by John Kitchin. See the License for information about copying.
Org-mode version = 8.2.6