X-Git-Url: https://git.donarmstrong.com/?p=org-ref.git;a=blobdiff_plain;f=doi-utils.org;h=68c74bcc3fde4ff88d3daa94bc5b934e99ddc400;hp=3fe93f0d8de08916e5b44f593e8bc87001f7a289;hb=b27a82139b93605379c12ce4221581990de2da44;hpb=2091cfcc6edd5da6a50f363dd0b6e9256c2bf8ab diff --git a/doi-utils.org b/doi-utils.org index 3fe93f0..68c74bc 100644 --- a/doi-utils.org +++ b/doi-utils.org @@ -570,7 +570,7 @@ prompt. Otherwise, you have to type or pste in a DOI." (s-match "^10" (buffer-substring (region-beginning) (region-end)))) - (buffer-susbstring (region-beginning) (region-end))) + (buffer-substring (region-beginning) (region-end))) ;; if the first entry in the kill-ring looks ;; like a DOI, let's use it. ((if (s-match "^10" (car kill-ring)) @@ -834,7 +834,9 @@ Here is our example bibtex entry. number = 6, pages = 1996, year = 2014, - doi = {10.1039/c3ee43874k}, + doi = {10.1039/c3ee43874k, + url = {http://dx.doi.org/10.1039/c3ee43874k}}, + } @@ -845,47 +847,55 @@ The idea is to query Crossref in a way that is likely to give us a hit relevant According to http://search.crossref.org/help/api we can send a query with a free form citation that may give us something back. We do this to get a list of candidates, and run a helm command to get the doi. -#+BEGIN_SRC emacs-lisp +#+BEGIN_SRC emacs-lisp :tangle doi-utils.el (defun doi-utils-crossref-citation-query () + "Query Crossref with the title of the bibtex entry at point to +get a list of possible matches. This opens a helm buffer to +select an entry. The default action inserts a doi and url field +in the bibtex entry at point. The second action opens the doi +url. If there is already a doi field, the function raises an +error." (interactive) (bibtex-beginning-of-entry) (let* ((entry (bibtex-parse-entry)) - (title (reftex-get-bib-field "title" entry)) (json-string) (json-data) (doi)) (unless (string= ""(reftex-get-bib-field "doi" entry)) (error "Entry already has a doi field")) - ;; clean up title for the crossref query - (setq title (replace-regexp-in-string "\n\\|\t\\|\s+" " " title)) (with-current-buffer (url-retrieve-synchronously (concat "http://search.crossref.org/dois?q=" - (url-hexify-string title))) + (url-hexify-string (org-ref-bib-citation)))) (setq json-string (buffer-substring url-http-end-of-headers (point-max))) (setq json-data (json-read-from-string json-string))) - (let* ((name (format "Crossref hits for %s" title)) + (let* ((name (format "Crossref hits for %s" (org-ref-bib-citation))) (helm-candidates (mapcar (lambda (x) (cons - (cdr (assoc 'fullCitation x)) + (concat + (cdr (assoc 'fullCitation x)) + " " + (cdr (assoc 'doi x))) (cdr (assoc 'doi x)))) json-data)) (source `((name . ,name) (candidates . ,helm-candidates) ;; just return the candidate - (action . (lambda (candidate) - candidate ))))) - (setq doi - (helm :sources '(source))) - - (when doi - (bibtex-make-field "doi") - (backward-char) - ;; crossref returns doi url, but I prefer only a doi for the doi field - (insert (replace-regexp-in-string "^http://dx.doi.org/" "" doi)))))) + (action . (("Insert doi and url field" . (lambda (doi) + (bibtex-make-field "doi") + (backward-char) + ;; crossref returns doi url, but I prefer only a doi for the doi field + (insert (replace-regexp-in-string "^http://dx.doi.org/" "" doi)) + (when (string= ""(reftex-get-bib-field "url" entry)) + (bibtex-make-field "url") + (backward-char) + (insert doi)))) + ("Open url" . (lambda (doi) + (browse-url doi)))))))) + (helm :sources '(source))))) #+END_SRC #+RESULTS: @@ -893,7 +903,61 @@ According to http://search.crossref.org/help/api we can send a query with a free +* 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. + +#+BEGIN_SRC emacs-lisp :tangle doi-utils.el +(defun doi-utils-add-entry-from-crossref-query (query bibtex-file) + (interactive (list + (read-input + "Query: " + ;; now set initial input + (cond + ;; If region is active assume we want it + ((region-active-p) + (replace-regexp-in-string + "\n" " " + (buffer-substring (region-beginning) (region-end)))) + ;; type or paste it in + (t + nil))) + (ido-completing-read + "Bibfile: " + (append (f-entries "." (lambda (f) (f-ext? f "bib"))) + org-ref-default-bibliography)))) + (let* ((json-string) + (json-data) + (doi)) + + (with-current-buffer + (url-retrieve-synchronously + (concat + "http://search.crossref.org/dois?q=" + (url-hexify-string query))) + (setq json-string (buffer-substring url-http-end-of-headers (point-max))) + (setq json-data (json-read-from-string json-string))) + (let* ((name (format "Crossref hits for %s" + ;; remove carriage returns. they cause problems in helm. + (replace-regexp-in-string "\n" " " query))) + (helm-candidates (mapcar (lambda (x) + (cons + (concat + (cdr (assoc 'fullCitation x)) + " " + (cdr (assoc 'doi x))) + (cdr (assoc 'doi x)))) + json-data)) + (source `((name . ,name) + (candidates . ,helm-candidates) + ;; just return the candidate + (action . (("Insert bibtex entry" . (lambda (doi) + (doi-utils-add-bibtex-entry-from-doi + (replace-regexp-in-string "^http://dx.doi.org/" "" doi) ,bibtex-file))) + ("Open url" . (lambda (doi) + (browse-url doi)))))))) + (helm :sources '(source))))) +#+END_SRC ** json @@ -1103,7 +1167,8 @@ Here is a list of helm candidates #+END_SRC #+RESULTS: -#+BEGIN_SRC emacs-lisp +#+BEGIN_SRC emacs-lisp :tangle no + (((fullCitation . "Ann M. Deml, Vladan Stevanovi\304\207, Christopher L. Muhich, Charles B. Musgrave, Ryan O'Hayre, 2014, 'Oxide enthalpy of formation and band gap energy as accurate descriptors of oxygen vacancy formation energetics', Energy & Environmental Science, vol. 7, no. 6, p. 1996") (year . "2014") (coins . "ctx_ver=Z39.88-2004&rft_id=info%3Adoi%2Fhttp%3A%2F%2Fdx.doi.org%2F10.1039%2Fc3ee43874k&rfr_id=info%3Asid%2Fcrossref.org%3Asearch&rft.atitle=Oxide+enthalpy+of+formation+and+band+gap+energy+as+accurate+descriptors+of+oxygen+vacancy+formation+energetics&rft.jtitle=Energy+%26+Environmental+Science&rft.date=2014&rft.volume=7&rft.issue=6&rft.spage=1996&rft.aufirst=Ann+M.&rft.aulast=Deml&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Ajournal&rft.genre=article&rft.au=Ann+M.+Deml&rft.au=+Vladan+Stevanovi%C4%87&rft.au=+Christopher+L.+Muhich&rft.au=+Charles+B.+Musgrave&rft.au=+Ryan+O%27Hayre") @@ -1187,36 +1252,114 @@ Here is a list of helm candidates ...) #+END_SRC -* end of file -#+BEGIN_SRC emacs-lisp :tangle doi-utils.el -(provide 'doi-utils) -#+END_SRC -* load -#+BEGIN_SRC emacs-lisp :tangle no -(org-babel-load-file "doi-utils.org") -#+END_SRC -#+RESULTS: -: Loaded doi-utils.el +* ISBN utility +These are not really doi utilities, but for now I am putting them here. +I found this on the web. It can be handy, but the bibtex entry has a lot of stuff in it. +#+BEGIN_SRC emacs-lisp :tangle doi-utils.el +(defun isbn-to-bibtex-lead (isbn) + "Search lead.to for ISBN bibtex entry. You have to copy the entry if it is on the page to your bibtex file." + (interactive "sISBN: ") +(browse-url +(format "http://lead.to/amazon/en/?key=%s+&si=all&op=bt&bn=&so=sa&ht=us" isbn))) +#+END_SRC +Here we get isbn metadata and build a bibtex entry. +http://xisbn.worldcat.org/xisbnadmin/doc/api.htm#getmetadata -#+BEGIN_SRC emacs-lisp -(setq data '(("John" . "john@email.com") - ("Jim" . "jim@email.com") - ("Jane" . "jane@email.com") - ("Jill" . "jill@email.com"))) +#+BEGIN_SRC emacs-lisp :tangle doi-utils.el +(defun isbn-to-bibtex (isbn bibfile) + "Get bibtex entry for ISBN and insert it into BIBFILE unless an +entry with the generated key already exists in the file." + (interactive + (list + (read-input + "ISBN: " + ;; now set initial input + (cond + ;; If region is active and it starts with a number, we use it + ((and (region-active-p) + (s-match "^[0-9]" (buffer-substring (region-beginning) (region-end)))) + (buffer-substring (region-beginning) (region-end))) + ;; if first entry in kill ring starts with a number assume it is an isbn + ;; and use it as the guess + ((if (s-match "^[0-9]" (car kill-ring)) + (car kill-ring))) + ;; type or paste it in + (t + nil))) + (ido-completing-read + "Bibfile: " + (append (f-entries "." (lambda (f) (f-ext? f "bib"))) + org-ref-default-bibliography)))) + + (let* ((results (with-current-buffer + (url-retrieve-synchronously + (format + "http://xisbn.worldcat.org/webservices/xid/isbn/%s?method=getMetadata&format=json&fl=*" + isbn)) + (json-read-from-string + (buffer-substring url-http-end-of-headers (point-max))))) + (status (cdr (nth 1 results))) + (metadata (aref (cdar results) 0)) + (new-entry) + (new-key)) + + ;; check if we got something + (unless (string= "ok" status) + (error "Status is %s" status)) + + ;; construct an alphabetically sorted bibtex entry. I assume ISBN numbers go + ;; with book entries. + (setq new-entry + (concat "\n@book{,\n" + (mapconcat + 'identity + (loop for field in (-sort 'string-lessp (mapcar 'car metadata)) + collect + (format " %s={%s}," field (cdr (assoc field metadata)))) + "\n") + "\n}\n")) + + ;; build entry in temp buffer to get the key so we can check for duplicates + (setq new-entry (with-temp-buffer + (insert new-entry) + (org-ref-clean-bibtex-entry) + (setq new-key (bibtex-key-in-head)) + (buffer-string))) + (find-file bibfile) + (goto-char (point-min)) + (when (search-forward new-key nil t) + (beep) + (setq new-key (read-input + (format "%s already exists. Enter new key (C-g to cancel): " new-key) + new-key))) + (goto-char (point-max)) + (insert new-entry) + ;; set key. It is simplest to just replace it, even if it is the same. + (bibtex-beginning-of-entry) + (re-search-forward bibtex-entry-maybe-empty-head) + (if (match-beginning bibtex-key-in-head) + (delete-region (match-beginning bibtex-key-in-head) + (match-end bibtex-key-in-head))) + (insert new-key) + (bibtex-fill-entry) + (save-buffer))) +#+END_SRC -(setq some-helm-source - `((name . "HELM at the Emacs") - (candidates . ,(mapcar 'car data)) - (action . (lambda (candidate) - (message-box "%s" (cdr (assoc candidate data))))))) -(message-box "you chose %s" (helm :sources '(some-helm-source))) + +* end of file +#+BEGIN_SRC emacs-lisp :tangle doi-utils.el +(provide 'doi-utils) +#+END_SRC +* load +#+BEGIN_SRC emacs-lisp :tangle no +(org-babel-load-file "doi-utils.org") #+END_SRC #+RESULTS: -: you chose jim@email.com +: Loaded doi-utils.el