bib2html.py: Add incollection bibtype
[shutils.git] / bib2html.py
1 #!/usr/bin/env python3
2 """Creates a webpage with all entries of a .bib file"""
3
4 __version__ = "1.1"
5
6 __author__ = "Stefan Huber"
7 __email__ = "shuber@sthu.org"
8 __copyright__ = "Copyright 2013, Stefan Huber"
9
10 __license__ = "MIT"
11
12 # Permission is hereby granted, free of charge, to any person
13 # obtaining a copy of this software and associated documentation
14 # files (the "Software"), to deal in the Software without
15 # restriction, including without limitation the rights to use,
16 # copy, modify, merge, publish, distribute, sublicense, and/or sell
17 # copies of the Software, and to permit persons to whom the
18 # Software is furnished to do so, subject to the following
19 # conditions:
20 #
21 # The above copyright notice and this permission notice shall be
22 # included in all copies or substantial portions of the Software.
23 #
24 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
26 # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
28 # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
29 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
31 # OTHER DEALINGS IN THE SOFTWARE.
32
33
34 import os, sys, getopt, re
35 import dateutil.parser
36
37
38 def format_latex(text):
39 # Get rid of matching dollar signs
40 text = re.sub(r'\$([^\$]*)\$', r'\1', text)
41
42 # Replace text
43 subst = {
44 '\\"a': 'ä',
45 '\\"o': 'ö',
46 '\\"u': 'u',
47 '\mathcal': '',
48 '{': '',
49 '}': '',
50 '\\': '',
51 '~': ' ',
52 '---': '–',
53 '--': '–',
54 }
55
56 for a, b in subst.items():
57 text = text.replace(a, b)
58
59 return text
60
61 def format_field_span(type, value):
62 return "<span class=bibentry_" + type + ">" + format_latex(value) + "</span>"
63
64 def format_field(bibentry, field, pre='', post=''):
65 if field in bibentry.fields:
66 if bibentry.fields[field] != "":
67 return format_field_span(field, pre + bibentry.fields[field] + post)
68 return ""
69
70 def format_author(a):
71 return ' '.join(' '.join(p) for p in (a.first_names, a.middle_names, a.prelast_names, a.last_names, a.lineage_names) if p)
72
73 def format_authors(entry):
74 return ", ".join([format_author(a) for a in entry.persons['author']])
75
76
77 def format_details_article(entry):
78
79 where = format_field(entry, 'journal')
80
81 line = []
82 line.append(format_field(entry, 'pages', pre='pp. '))
83 line.append(format_field(entry, 'volume', pre='vol. ') + \
84 format_field(entry, 'number', pre='(', post=')'))
85 line.append(format_field(entry, 'month', post=' ') + \
86 format_field(entry, 'year'))
87 line.append(format_field(entry, 'note'))
88
89 line = filter(lambda l: l != "", line)
90 return [where, ", ".join(line)]
91
92 def format_details_inproceedings(entry):
93 where = format_field(entry, 'booktitle')
94
95 line = []
96 line.append(format_field(entry, 'pages', pre='pp. '))
97 line.append(format_field(entry, 'address'))
98 line.append(format_field(entry, 'month', post=' ') + \
99 format_field(entry, 'year'))
100 line.append(format_field(entry, 'isbn', pre='ISBN '))
101 line.append(format_field(entry, 'note'))
102
103 line = filter(lambda l: l != "", line)
104 return [where, ", ".join(line)]
105
106 def format_details_incollection(entry):
107 where = format_field(entry, 'booktitle')
108
109 line = []
110 line.append(format_field(entry, 'publisher'))
111 line.append(format_field(entry, 'pages', pre='pp. '))
112 line.append(format_field(entry, 'address'))
113 line.append(format_field(entry, 'month', post=' ') + \
114 format_field(entry, 'year'))
115 line.append(format_field(entry, 'isbn', pre='ISBN '))
116 line.append(format_field(entry, 'note'))
117
118 line = filter(lambda l: l != "", line)
119 return [where, ", ".join(line)]
120
121 def format_details_thesis(entry):
122 line = []
123 line.append(format_field(entry, 'school'))
124 line.append(format_field(entry, 'month', post=' ') + \
125 format_field(entry, 'year'))
126 line.append(format_field(entry, 'note'))
127
128 line = filter(lambda l: l != "", line)
129 return [", ".join(line)]
130
131 def format_details_book(entry):
132 line = []
133 line.append(format_field(entry, 'publisher'))
134 line.append(format_field(entry, 'isbn', pre='ISBN '))
135 line.append(format_field(entry, 'month', post=' ') + \
136 format_field(entry, 'year'))
137 line.append(format_field(entry, 'note'))
138
139 line = filter(lambda l: l != "", line)
140 return [", ".join(line)]
141
142 def format_details_patent(entry):
143 line = []
144 line.append(format_field(entry, 'number', pre='Pat. '))
145 line.append(format_field(entry, 'month', post=' ') + \
146 format_field(entry, 'year'))
147 line.append(format_field(entry, 'note'))
148
149 line = filter(lambda l: l != "", line)
150 return [", ".join(line)]
151
152 def format_links(entry):
153 doi = format_field(entry, 'doi', pre='<a href="http://dx.doi.org/', post='">[DOI]</a>')
154 webpdf = format_field(entry, 'webpdf', pre='<a href="', post='">[PDF]</a>')
155 weblink = format_field(entry, 'weblink', pre='<a href="', post='">[link]</a>')
156 url = format_field(entry, 'url', pre='<a href="', post='">[url]</a>')
157 webslides = format_field(entry, 'webslides', pre='<a href="', post='">[slides]</a>')
158 weberrata = format_field(entry, 'weberrata', pre='<a href="',
159 post='">[errata]</a>')
160 return " ".join([doi, webpdf, weblink, url, webslides, weberrata])
161
162 def format_entry(entry):
163 lines = []
164 lines.append(format_field(entry, 'title', pre="<b>", post="</b>"))
165 lines.append(format_field_span('author', format_authors(entry)))
166
167 if entry.type=='article':
168 lines.extend(format_details_article(entry))
169 elif entry.type=='inproceedings':
170 lines.extend(format_details_inproceedings(entry))
171 elif entry.type=='incollection':
172 lines.extend(format_details_incollection(entry))
173 elif entry.type=='book':
174 lines.extend(format_details_book(entry))
175 elif entry.type=='patent':
176 lines.extend(format_details_patent(entry))
177 elif entry.type in ['mastersthesis', 'phdthesis']:
178 lines.extend(format_details_thesis(entry))
179 else:
180 lines.append("Unknown type <b>'" + entry.type + "'</b>")
181
182 lines.append(format_field(entry, 'webnote'))
183 lines.append(format_links(entry))
184
185 lines = filter(lambda l: l != "", lines)
186 return "<br/>\n".join(lines)
187
188
189 def entryDateSortKey(p):
190 k, e = p
191
192 if 'date' in e.fields:
193 return e.fields['date']
194
195 month2num = { 'jan' : '01', 'feb' : '02', 'mar' : '03', \
196 'apr' : '04', 'may' : '05', 'jun' : '06', \
197 'jul' : '07', 'aug' : '08', 'sep' : '09', \
198 'oct' : '10', 'nov' : '11', 'dec' : '12'}
199
200 if not 'month' in e.fields:
201 return e.fields['year']
202
203 month = e.fields['month'].lower()[0:3]
204 if month in month2num:
205 month = month2num[month]
206 else:
207 month = ""
208
209 return e.fields['year'] + "-" + month
210
211
212 def entryGetYear(e):
213 if 'year' in e.fields:
214 return e.fields['year']
215
216 if 'date' in e.fields:
217 dt = dateutil.parser.isoparse(e.fields['date'])
218 return str(dt.year)
219
220 return None
221
222
223 def usage():
224 """Print usage text of this program"""
225
226 print("""Usage:
227 {0} -i FILE
228 {0} -h
229
230 OPTIONS:
231 -h print this text
232 -i .bib file
233 """.format(sys.argv[0]))
234
235 if __name__ == "__main__":
236
237 bibfile = None
238
239 try:
240 opts, args = getopt.getopt(sys.argv[1:], "hi:")
241
242 for opt, arg in opts:
243 if opt == "-h":
244 usage()
245 sys.exit(os.EX_OK)
246 elif opt == "-i":
247 bibfile = arg
248 else:
249 print("Unknown option '", opt, "'.")
250
251 except getopt.GetoptError as e:
252 print("Error parsing arguments:", e)
253 usage()
254
255 if bibfile == None:
256 print("You need to specify a bibfile")
257 usage()
258 sys.exit(os.EX_USAGE)
259
260
261 from pybtex.database.input import bibtex
262 parser = bibtex.Parser()
263
264 from pybtex.style.formatting.unsrt import Style
265
266 bib_data = parser.parse_file(bibfile)
267 entries = bib_data.entries
268
269 years = list(set([entryGetYear(e) for e in entries.values()]))
270 years.sort(reverse=True)
271
272 for year in years:
273
274 print("<h2>" + year + "</h2>")
275
276 iteritems = list(entries.items())
277 iteritems.sort(key=entryDateSortKey, reverse=True)
278 for key, entry in iteritems:
279
280 if entryGetYear(entry) != year:
281 continue
282
283 print("<div class=bibentry>")
284 print("<a class=bibentry_key id={}>[{}]</a><br/><span class=bibentry_type>{}</span><br/>".format(key, key, entry.type))
285 e = format_entry(entry)
286 print(e)
287
288 print("</div>\n")