Skip to content

Instantly share code, notes, and snippets.

@sbirch
Created March 31, 2014 21:42
Show Gist options
  • Select an option

  • Save sbirch/9903010 to your computer and use it in GitHub Desktop.

Select an option

Save sbirch/9903010 to your computer and use it in GitHub Desktop.
A script to convert KeepassX XML exports to a CSV as consumed by 1Password. Will read from keepass.xml and write to keepass.csv in current working directory.
import xml.etree.ElementTree as ET
import csv
from collections import defaultdict
# Note that 1Password is quite particular about the kind of escaping you use.
# The default Excel dialect blows it up & there is in fact no Python dialect
# corresponding to 1Password's requirements due to http://bugs.python.org/issue12178
output = csv.writer(open('keepass.csv', 'wb'), doublequote=False, escapechar='\\', quoting=csv.QUOTE_ALL)
dom = ET.parse('keepass.xml')
entries = defaultdict(list)
# The Keepass XML file often has the same entries duplicated for past values
# of your password. You would think that you might figure out which one is
# correct via <creation>, <lastaccess> or <lastmod> but apparently this is
# not the case. As far as I can tell the most recent (i.e. the current entry)
# is the one which is written first in the file.
# This also means: if you have multiple entries that actually have the same
# title then only one will be kept.
for element in dom.iter('entry'):
assert set([child.tag for child in element]) == set([
'expire', 'icon', 'lastmod', 'creation', 'lastaccess', 'lastmod',
'comment', 'url', 'title', 'username', 'password'])
title = element.find('title').text
if title is None and element.find('username').text is None:
print 'Entry with no title and no username. Skipping:'
print ET.tostring(element)
continue
elif title is None:
title = element.find('username').text
entries[title].append(element)
#http://learn.agilebits.com/1Password4/Mac/en/KB/import.html#csv--comma-separated-values
for i, (title, elements) in enumerate(entries.items()):
element = elements[0]
location = element.find('url').text or ''
username = element.find('username').text or ''
password = element.find('password').text or ''
notes = '\n'.join(list(element.find('comment').itertext() or []))
output.writerow([x.replace('\\', '\\\\') for x in [title, location, username, password, notes]])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment