forked from jkitchin/org-ref
-
Notifications
You must be signed in to change notification settings - Fork 0
/
org-ref-pubmed.el
259 lines (210 loc) · 9.37 KB
/
org-ref-pubmed.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
;;; org-ref-pubmed.el --- Links and functions for Pubmed and NIH databases -*- lexical-binding: t; -*-
;; Copyright (C) 2015 John Kitchin
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
;; Keywords: convenience
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;* Introduction
;; This document is an experiment at creating a literate program to provide
;; functions for interacting with pubmed databases.
;; This library provides links that go to pubmed resources, e.g.
;; pmcid:PMC3498956
;;
;; pmid:23162369
;;
;; and nihmsid:NIHMS395714
;;
;; See http://www.ncbi.nlm.nih.gov/pmc/about/public-access-info/#p3 for details
;; of these identifiers.
;;
;; For PMID there is one interactive function that inserts a bibtex entry:
;; pubmed-insert-bibtex-from-pmid.
;; This library is complementary to [[./doi-utils.org]].
;;; Code:
;;* PMID (from PubMed) link and functions
;; A PMID is a number that identifies an entry in the Pubmed database. The PMID
;; is a unique reference number for PubMed citations. The PMID is a distinctly
;; different number from the PMCID and is used only for PubMed records.
(require 'dash)
(require 'org)
(require 'org-ref-utils)
(org-ref-link-set-parameters "pmid"
:follow (lambda (link-string) (browse-url (format "http://www.ncbi.nlm.nih.gov/pubmed/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://www.ncbi.nlm.nih.gov/pmc/articles/mid/%s\">pmid:%s</a>" keyword (or desc keyword))) ; no output for html
((eq format 'latex)
;; write out the latex command
(format "\\url{http://www.ncbi.nlm.nih.gov/pmc/articles/mid/%s}{%s}" keyword (or desc keyword))))))
;;** Get MEDLINE metadata
;; We can get bibliographic metadata from a pmid. Here we get the MEDLINE
;; text. The website wraps the data in <pre></pre> tags.
(defun pubmed-get-medline (pmid)
"Get MEDLINE text for PMID as a string."
(with-current-buffer
(url-retrieve-synchronously
(format "http://www.ncbi.nlm.nih.gov/pubmed/%s/?report=medline&format=text" pmid))
(goto-char (point-min))
(let ((p1 (search-forward "<pre>"))
(p2 (search-forward "</pre>")))
(buffer-substring (+ 1 p1) (- p2 6)))))
;;** Parse the PMID MEDLINE data
;; We can parse this into a data structure.
(defun pubmed-parse-medline (pmid)
"Parse the medline text for PMID and return a list of cons cells."
(let ((data '())
(p1)
(p2)
(tag)
(value))
(with-temp-buffer (insert (pubmed-get-medline pmid))
(goto-char (point-min))
(while (re-search-forward "\\(^[A-Z]\\{2,4\\}\\)\\s-*- "
nil t)
(setq tag (match-string 1))
;; point is at end of the search
(setq p1 (point))
;; now go to next tag
(re-search-forward "\\(^[A-Z]\\{2,4\\}\\)\\s-*- " nil t)
(setq p2 (- (match-beginning 1) 1))
(setq value (buffer-substring p1 p2))
(setq data (append data (list (cons tag value))))
;; now go back to last tag to get the next one
(goto-char p1)))
data))
;;** PMID to bibtex entry
;; The point of parsing the MEDLINE text is so we can make bibtex entries. We
;; only support Journal articles for now.
(defun pubmed-pmid-to-bibtex (pmid)
"Convert a PMID to a bibtex entry."
(let* ((data (pubmed-parse-medline pmid))
(type (downcase (cdr (assoc "PT" data))))
(title (cdr (assoc "TI" data)))
(authors (mapconcat 'cdr
(-filter (lambda (x)
(string= (car x) "FAU"))
data)
" and "))
(abstract (cdr (assoc "AB" data)))
(volume (cdr (assoc "VI" data)))
(issue (cdr (assoc "IP" data)))
(journal (cdr (assoc "JT" data)))
(year (cdr (assoc "DP" data)))
(pages (cdr (assoc "PG" data)))
(aid (cdr (assoc "AID" data))))
(cond
((string= type "journal article")
(concat "@article{,
author = {" authors "},
title = {" title "},
abstract = {" abstract "},
journal = {" journal "},
volume = {" volume "},
number = {" issue "},
year = {" (car (split-string year)) "},
pages = {" pages "},
doi = {" (replace-regexp-in-string " \\[doi\\]" "" aid) "},
}"))
(t
(message "No conversion for type: %s" type)))))
;; And we probably want to be able to insert a bibtex entry
;;;###autoload
(defun pubmed-insert-bibtex-from-pmid (pmid)
"Insert a bibtex entry at point derived from PMID.
You must clean the entry after insertion."
(interactive "sPMID: ")
(insert (pubmed-pmid-to-bibtex pmid)))
;;** PMID to xml
;; We can also get xml of the MEDLINE data. The web page here also wraps the xml
;; in a <pre> block and escapes the <> with < and >, which we have to
;; undo. I have not used this code for anything, so I am not sure how good the
;; xml code is.
;;;###autoload
(defun pubmed-get-medline-xml (pmid)
"Get MEDLINE xml for PMID as a string."
(interactive)
(with-current-buffer
(url-retrieve-synchronously
(format "http://www.ncbi.nlm.nih.gov/pubmed/%s/?report=xml&format=text" pmid))
(goto-char (point-min))
(while (search-forward "<" nil t)
(replace-match "<"))
(goto-char (point-min))
(while (search-forward ">" nil t)
(replace-match ">"))
(goto-char (point-min))
(let ((p1 (search-forward "<pre>"))
(p2 (search-forward "</pre>")))
(buffer-substring (+ 1 p1) (- p2 6)))))
;;* Pubmed Central (PMC) link
;; A PMCID starts with PMC and is followed by numbers. The PMCID is a unique
;; reference number or identifier that is assigned to every article that is
;; accepted into PMC. The PMCID is also used by recipients of NIH funding to
;; demonstrate compliance with the NIH Public Access policy. The PMCID can be
;; found in both PMC and PubMed.
;; Here we define a new link. Clicking on it simply opens a webpage to the
;; article.
(org-ref-link-set-parameters "pmcid"
:follow (lambda (link-string) (browse-url (format "http://www.ncbi.nlm.nih.gov/pmc/articles/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://www.ncbi.nlm.nih.gov/pmc/articles/%s\">pmcid:%s</a>" keyword (or desc keyword)))
((eq format 'latex)
(format "\\url{http://www.ncbi.nlm.nih.gov/pmc/articles/%s}{%s}" keyword (or desc keyword))))))
;;* NIHMSID
;; The NIHMSID is a preliminary article identifier that applies only to
;; manuscripts deposited through the NIHMS system. The NIHMSID is only valid for
;; compliance reporting for 90 days after the publication date of an
;; article. Once the Web version of the NIHMS submission is approved for
;; inclusion in PMC and the corresponding citation is in PubMed, the article
;; will also be assigned a PMCID.
(org-ref-link-set-parameters "nihmsid"
:follow (lambda (link-string) (browse-url (format "http://www.ncbi.nlm.nih.gov/pmc/articles/mid/%s" link-string)))
:export (lambda (keyword desc format)
(cond
((eq format 'html)
(format "<a href=\"http://www.ncbi.nlm.nih.gov/pmc/articles/mid//%s\">nihmsid:%s</a>" keyword (or desc keyword)))
((eq format 'latex)
;; write out the latex command
(format "\\url{http://www.ncbi.nlm.nih.gov/pmc/articles/mid/%s}{%s}" keyword (or desc keyword))))))
;;* Searching pubmed
;;;###autoload
(defun pubmed ()
"Open http://www.ncbi.nlm.nih.gov/pubmed in a browser."
(interactive)
(browse-url "http://www.ncbi.nlm.nih.gov/pubmed"))
;;;###autoload
(defun pubmed-advanced ()
"Open http://www.ncbi.nlm.nih.gov/pubmed/advanced in a browser."
(interactive)
(browse-url "http://www.ncbi.nlm.nih.gov/pubmed/advanced"))
;;;###autoload
(defun pubmed-simple-search (query)
"Open QUERY in Pubmed in a browser."
(interactive "sQuery: ")
(browse-url
(format "http://www.ncbi.nlm.nih.gov/pubmed/?term=%s" (url-hexify-string query))))
(org-ref-link-set-parameters "pubmed-search"
:follow (lambda (query)
"Open QUERY in a `pubmed-simple-search'."
(pubmed-simple-search query))
:export (lambda (query desc format)
(let ((url (format "http://www.ncbi.nlm.nih.gov/pubmed/?term=%s" (url-hexify-string query))))
(cond
((eq format 'html)
(format "<a href=\"%s\">%s</a>" url (or desc (concat "pubmed-search:" query))))
((eq format 'latex)
(format "\\href{%s}{%s}" url (or desc (concat "pubmed-search:" query))))))))
(provide 'org-ref-pubmed)
;;; org-ref-pubmed.el ends here