XBEL2Moin
This script takes a bookmarks file in XBEL format on the command line and spits out a Wiki page in MoinMoin format on standard out. Bookmark folder titles are rendered as headings with increasing levels according to the hierarchy depth of the folders. Run xbel2moin.py -h for help on command line options.
The script requires Python >= 2.3 and the ElementTree library
Download: xbel2moin.py
1 #!/usr/bin/env python
2 # -*- coding: UTF-8 -*-
3 """Converts an XBEL bookmark file into a flat listing in MoinMoin wiki format.
4 """
5
6 # standard-library modules
7 import os
8 import re
9 import sys
10 from optparse import OptionParser
11
12 # third-party modules
13 import elementtree.ElementTree as ET
14
15 __program__ = "xbel2moin.py"
16 __author__ = "Christopher Arndt"
17 __version__ = "0.1"
18 __revision__ = "$Rev: 142 $"
19 __date__ = "$Date: 2007-06-13 23:34:39 +0200 (Mi, 13 Jun 2007) $"
20 __copyright__ = "MIT license"
21
22 __usage__ = """\
23 %prog [OPTIONS] <XBEL file>
24 """
25
26 FOOTER = """\
27
28 ----
29
30 ''generated by [attachment:xbel2moin.py xbel2moin.py] on %(date)s from
31 [attachment:%(source)s %(source)s]''
32 """
33
34
35 def usage():
36 optparser.print_help()
37
38 mangle_re = re.compile(r'\s+', re.DOTALL)
39 def manglews(text):
40 return mangle_re.sub(u' ', text.strip())
41
42 def make_heading(text, lvl):
43 return u"%s %s %s\n" % ('=' * lvl, text, '=' * lvl)
44
45 def make_bookmark(elem):
46 title = elem.find('title')
47 if ET.iselement(title):
48 titletext = title.text.strip()
49 else:
50 titletext = u'Unnamed bookmark'
51 desc = elem.find('desc')
52 if ET.iselement(desc):
53 desctext = u'\n\n ' + manglews(desc.text)
54 else:
55 desctext = u""
56 return u"'''[%s %s]'''%s\n" % (elem.get('href', u'#'), titletext,
57 desctext)
58
59 def parse_folder(elem, headlvl):
60 text = []
61 title = elem.find('title')
62 if ET.iselement(title):
63 text.append(make_heading(title.text, headlvl+1))
64 elif headlvl != 0:
65 text.append(make_heading(u'Unnamed folder', headlvl+1))
66 if headlvl == 0 and options.toc:
67 text.append(u'[[TableOfContents([%i])]]\n' % options.tocdepth)
68 for subelem in elem:
69 if subelem.tag == 'folder':
70 text.append(parse_folder(subelem, headlvl+1))
71 if subelem.tag == 'bookmark':
72 text.append(make_bookmark(subelem))
73 return u"\n".join(text)
74
75 def xbel2moin(filename):
76 tree = ET.parse(filename)
77 root = tree.getroot()
78 headlvl = 0
79 doc = parse_folder(root, headlvl)
80 if options.footer:
81 import locale
82 import time
83 locale.setlocale(locale.LC_ALL, '')
84 doc += FOOTER % dict(date=time.strftime('%x %X'), source=filename)
85 return doc
86
87 def main(args):
88 global options, optparser
89
90 optparser = OptionParser(prog=__program__, usage=__usage__,
91 version=__version__, description=__doc__)
92 # optparser.add_option("-v", "--verbose",
93 # action="store_true", dest="verbose", default=False,
94 # help="Print what's going on to stdout.")
95 optparser.add_option("-t", "--toc",
96 action="store_true", dest="toc", default=False,
97 help="Add a table of contents macro after the first heading.")
98 optparser.add_option("-d", "--toc-depth",
99 action="store", type="int", dest="tocdepth", default=3,
100 help="How many heading levels to display in the TOC (default 3).")
101 optparser.add_option("-f", "--add-footer",
102 action="store_true", dest="footer", default=False,
103 help='Add a footer with a "generated by" notice.')
104
105 (options, args) = optparser.parse_args(args=args)
106 if args:
107 print xbel2moin(args[0])
108 else:
109 usage()
110 return 2
111 return 0
112
113 if __name__ == '__main__':
114 sys.exit(main(sys.argv[1:]))