Skip to content

Instantly share code, notes, and snippets.

@scribu
Last active August 5, 2019 09:59
Show Gist options
  • Save scribu/7442170 to your computer and use it in GitHub Desktop.
Save scribu/7442170 to your computer and use it in GitHub Desktop.
Convert notes from Tomboy XML to Evernote XML
isodate==0.4.9
lxml==3.2.4
from __future__ import print_function
import glob
import lxml.etree as ET
import os
import sys
import isodate
import datetime
TOMBOY_CAT_PREFIX = 'system:notebook:'
EV_EXPORT_XML = u"""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export3.dtd">
"""
EV_NOTE_XML = u"""<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
"""
EV_DATE_FORMAT = '%Y%m%dT%H%M%SZ'
def el(name):
return '{http://beatniksoftware.com/tomboy}' + name
def innertext(tag):
"""Convert Tomboy XML to Markdown"""
text = (tag.text or '')
if tag.tag == el('bold'):
text = '**' + text.strip() + '**'
elif tag.tag == el('list-item'):
text = '- ' + text
return text + ''.join(innertext(e) for e in tag) + (tag.tail or '')
def append_content(path, content):
with open(path, 'r') as f:
existingContent = f.read().decode('utf8')
if -1 == existingContent.find(content):
with open(path, 'a') as f:
content = u'\n* *\n *\n\n' + content
f.write(content.encode('utf8'))
def extract_data(path):
root = ET.parse(path).getroot()
tags = []
category = None
tagsEl = root.find(el('tags'))
if tagsEl is not None:
for tagEl in tagsEl:
tag = tagEl.text
if tag.startswith(TOMBOY_CAT_PREFIX):
category = tag.replace(TOMBOY_CAT_PREFIX, '')
else:
tags.append(tag)
if 'system:template' in tags:
return None
note = {}
title = root.find(el('title')).text
contentTag = root.find(el('text')).find(el('note-content'))
content = innertext(contentTag)
note['title'] = title
note['content'] = content.replace(title, '').lstrip()
for tag, key in [('create-date', 'created'), ('last-change-date', 'updated')]:
dateTag = root.find(el(tag))
note[key] = isodate.parse_datetime(dateTag.text)
note['tags'] = tags
note['category'] = category
return note
def prepare_content(text_content):
tree = ET.Element('en-note')
for line in text_content.split('\n'):
el = ET.SubElement(tree, 'div')
line = line.strip()
if line != '':
el.text = line
else:
ET.SubElement(el, 'br')
return EV_NOTE_XML + ET.tostring(tree, pretty_print=True)
def export_one(note, path, export_dt):
tree = ET.Element('en-export', {
'application': 'Tomboy Exporter',
'version': '0.1',
'export-date': export_dt.strftime(EV_DATE_FORMAT)
})
noteTag = ET.SubElement(tree, 'note')
titleTag = ET.SubElement(noteTag, 'title')
titleTag.text = note['title']
contentTag = ET.SubElement(noteTag, 'content')
contentTag.text = ET.CDATA(prepare_content(note['content']))
for key in ['created', 'updated']:
dateTag = ET.SubElement(noteTag, key)
dateTag.text = note[key].strftime(EV_DATE_FORMAT)
for tag in note['tags']:
tagEl = ET.SubElement(noteTag, 'tag')
tagEl.text = tag
with open(path, 'w') as f:
f.write(EV_EXPORT_XML)
ET.ElementTree(tree).write(f)
f.write('\n')
def main():
if len(sys.argv) < 2:
print('usage: python tomboy-export.py <tomboy-dir>', file=sys.stderr)
sys.exit(1)
export_dt = datetime.datetime.now()
count = 0
for path in glob.glob(sys.argv[1] + '/*.note'):
note = extract_data(path)
if not note:
continue
notePath = 'export/'
if note['category']:
notePath = os.path.join(notePath, note['category'])
if not os.path.exists(notePath):
os.makedirs(notePath)
notePath = os.path.join(notePath, note['title'].replace('/', '|') + '.enex')
export_one(note, notePath, export_dt)
count += 1
print('Exported %s notes.' % count)
main()
@khurshid-alam
Copy link

@scribu It doesn't respect bold or italic format. When I import it through api, all formattings are lost.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment