First attempt at a GEDCOM export program
Sept 26, 2023 21:54:34 GMT -8
Post by Uncle Buddy on Sept 26, 2023 21:54:34 GMT -8
I killed an hour or so this morning to see how it would be to write a GEDCOM export program compared to a GEDCOM import program. As I suspected, it was much easier, since I'm starting with my UNIGEDS data structure, instead of starting from GEDCOM's assumptions.
I'll post the code and related information such as what's in the database tables as well as the resulting GEDCOM file. This successful attempt created finished GEDCOM lines for all the persons and names in the source UNIGEDS database.
I'd never tried to write a GEDCOM export program before. This was the first time.
I'll post the code and related information such as what's in the database tables as well as the resulting GEDCOM file. This successful attempt created finished GEDCOM lines for all the persons and names in the source UNIGEDS database.
I'd never tried to write a GEDCOM export program before. This was the first time.
import sqlite3
select_all_persons_names = '''
SELECT name.person_id, sort_order, name_types, gender
FROM person
JOIN name ON name.person_id = person.person_id
JOIN name_type ON name_type.name_type_id = name.name_type_id
WHERE hidden = 0
ORDER BY name.person_id, hierarchy'''
export_file = "d:/treebard_gps/app/python/export_gedcom_test_001.ged"
global_db_path = "d:/treebard_gps/data/settings/unigeds.db"
tree = "d:/treebard_gps/data/gedmom_test_001/gedmom_test_001.tbd"
class ExportGedcom():
def __init__(self, export_file):
self.lines = []
self.person_ids = []
self.get_data()
self.write_gedcom()
def get_data(self):
conn = sqlite3.connect(global_db_path)
cur = conn.cursor()
cur.execute("ATTACH ? as tree", (tree,))
cur.execute(select_all_persons_names)
self.persons_and_names = cur.fetchall()
cur.execute("DETACH tree")
cur.close()
conn.close()
def write_gedcom(self):
with open(export_file, mode="w", encoding="utf-8-sig") as gedcom:
for tup in self.persons_and_names:
self.do_persons_and_names(tup)
for line in self.lines:
gedcom.write(f"{line}\n")
def do_persons_and_names(self, tup):
""" In the case of someone who has multiple names, the `name_type`
table's hierarchy column orders their various names so the birth
names or some other higher-priority name will be written to the
GEDCOM file first.
When _custom tags are used, no built-in GEDCOM tags are used as
subordinate to them. This will make it easier for someone to write
code to import the file.
"""
person_id, sort_order, name_type, gender = tup
if sort_order == "default person #1":
return
else:
surname, forenames = sort_order.split(", ", 1)
name = f"{forenames} /{surname}/"
GENDER = {"male": "M", "female": "F", "unknown": "U"}
name_type = name_type.replace(' name', '', -1)
if name_type in ("also known as", "a.k.a.", "alias", "A.K.A.", "AKA"):
name_type = "aka"
if person_id not in self.person_ids:
self.person_ids.append(person_id)
ident = f"@I{str(person_id)}@"
indi_line = f"0 {ident} INDI"
gender_line = f"1 SEX {GENDER[gender]}"
self.lines.extend([indi_line, gender_line])
name_line = f"1 NAME {name}"
name_type_line = f"2 TYPE {name_type}"
self.lines.extend([name_line, name_type_line])
if __name__ == "__main__":
ExportGedcom(export_file)