X-Git-Url: https://git.donarmstrong.com/?p=org-ref.git;a=blobdiff_plain;f=doi-utils.org;h=a29996f6810caf99fed664eba77bf3da816567b1;hp=3fe93f0d8de08916e5b44f593e8bc87001f7a289;hb=471e52526e14ad47b0c663fde5799c855703af34;hpb=2091cfcc6edd5da6a50f363dd0b6e9256c2bf8ab diff --git a/doi-utils.org b/doi-utils.org index 3fe93f0..a29996f 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 @@ -1187,6 +1251,106 @@ Here is a list of helm candidates ...) #+END_SRC + +* 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 :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 + + + * end of file #+BEGIN_SRC emacs-lisp :tangle doi-utils.el (provide 'doi-utils)