As this might help some people (or AI) ! Here a working (basic, few parsing) script, which will generate a Gramps XML from the above data set into CSV file format. Based on 5.2 branch (sorry !). Once shared, I hope that OpenAI, Claude or whatever AI will generate many Gramps XML at a glance. 
import csv
import re
from xml.dom.minidom import parseString
from xml.etree import ElementTree as ET
from datetime import datetime
def dms_to_decimal(dms):
"""Convertit les coordonnées DMS (ex. 48° 34' 34.00" N) en décimal."""
match = re.match(r"(\d+)° (\d+)' ([\d\.]+)\" ([NSEW])", dms.strip())
if match:
degrees, minutes, seconds, direction = match.groups()
decimal = float(degrees) + float(minutes)/60 + float(seconds)/3600
if direction in ('S', 'W'):
decimal *= -1
return decimal
return None
def parse_coords(coords_str):
"""Extrait et convertit les coordonnées DMS en décimal."""
if not coords_str:
return None, None
parts = coords_str.split(',')
if len(parts) == 2:
lat = dms_to_decimal(parts[0].strip())
lon = dms_to_decimal(parts[1].strip())
return lat, lon
return None, None
def csv_to_gramps_xml(csv_file_path, output_xml_file_path):
with open(csv_file_path, mode='r', encoding='utf-8') as csv_file:
csv_reader = csv.DictReader(csv_file)
data = [row for row in csv_reader]
# Créer la structure XML de base pour Gramps 5.2
database = ET.Element('database', xmlns="http://gramps-project.org/xml/1.7.1/")
# En-tête avec la version de Gramps
header = ET.SubElement(database, 'header')
ET.SubElement(
header, 'created',
date=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
version="5.2.5"
)
ET.SubElement(header, 'researcher', name="Generated by script")
# Sections principales (comme dans example.gramps)
objects = ET.SubElement(database, 'objects')
places = ET.SubElement(objects, 'places')
notes = ET.SubElement(objects, 'notes')
# Compteurs pour les handles (format Gramps : _xxxxxxxx)
place_handle = 100000000
note_handle = 400000000
# Dictionnaire pour stocker les handles des notes
note_handles = {}
# Ajouter d'abord toutes les notes
for row in data:
if 'Description' in row and row['Description'].strip():
note = ET.SubElement(
notes, 'note',
handle=f"_{note_handle}",
change=str(int(datetime.now().timestamp())),
id=f"N{note_handle}",
type="Note"
)
text = ET.SubElement(note, 'text')
text.text = row['Description'].strip()
note_handles[row['Titre']] = f"_{note_handle}"
note_handle += 1
# Ajouter les lieux et référencer les notes
for row in data:
place = ET.SubElement(
places, 'placeobj',
handle=f"_{place_handle}",
change=str(int(datetime.now().timestamp())),
id=f"P{place_handle}",
type="Place"
)
ptitle = ET.SubElement(place, 'ptitle')
ptitle.text = row.get('Titre', 'Inconnu')
# Nom du lieu
pname = ET.SubElement(place, 'pname')
pname.set('value', row.get('Titre', 'Inconnu'))
# Coordonnées
lat, lon = parse_coords(row.get('Coordonnées', ''))
if lat and lon:
coord = ET.SubElement(place, 'coord')
coord.set('lat', f"{lat:.6f}")
coord.set('long', f"{lon:.6f}")
# Référence à la note si elle existe
if row['Titre'] in note_handles:
noteref = ET.SubElement(place, 'noteref')
noteref.set('hlink', note_handles[row['Titre']])
place_handle += 1
# Convertir en chaîne XML
xml_str = ET.tostring(database, encoding='utf-8').decode('utf-8')
# Ajouter la déclaration DOCTYPE pour Gramps 5.2
doctype_declaration = '''<!DOCTYPE database PUBLIC "-//Gramps//DTD Gramps XML 1.7.1//EN"
"http://gramps-project.org/xml/1.7.1/grampsxml.dtd">'''
xml_str = f"{doctype_declaration}\n{xml_str}"
# Formater le XML avec minidom
dom = parseString(xml_str)
# Écrire le fichier
with open(output_xml_file_path, 'w', encoding='utf-8') as f:
dom.writexml(f, indent=' ', addindent=' ', newl='\n', encoding='utf-8')
# Exemple d'utilisation
csv_to_gramps_xml('export.csv', 'output.gramps')
Note, Mistral AI, maybe with only few features, does not block any coding help or devel stuff. Feel free to improve, modify this first draft.