gedcom-x 0.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gedcom_x-0.5.dist-info/METADATA +17 -0
- gedcom_x-0.5.dist-info/RECORD +37 -0
- gedcom_x-0.5.dist-info/WHEEL +5 -0
- gedcom_x-0.5.dist-info/top_level.txt +1 -0
- gedcomx/Address.py +100 -0
- gedcomx/Agent.py +83 -0
- gedcomx/Attribution.py +116 -0
- gedcomx/Conclusion.py +137 -0
- gedcomx/Coverage.py +26 -0
- gedcomx/Date.py +29 -0
- gedcomx/Document.py +42 -0
- gedcomx/Event.py +195 -0
- gedcomx/EvidenceReference.py +11 -0
- gedcomx/Fact.py +462 -0
- gedcomx/Gedcom.py +345 -0
- gedcomx/GedcomX.py +1105 -0
- gedcomx/Gender.py +48 -0
- gedcomx/Group.py +37 -0
- gedcomx/Identifier.py +89 -0
- gedcomx/Name.py +241 -0
- gedcomx/Note.py +65 -0
- gedcomx/OnlineAccount.py +10 -0
- gedcomx/Person.py +178 -0
- gedcomx/PlaceDescription.py +47 -0
- gedcomx/PlaceReference.py +31 -0
- gedcomx/Qualifier.py +27 -0
- gedcomx/Relationship.py +116 -0
- gedcomx/Serialization.py +37 -0
- gedcomx/SourceCitation.py +20 -0
- gedcomx/SourceDescription.py +241 -0
- gedcomx/SourceReference.py +168 -0
- gedcomx/Subject.py +73 -0
- gedcomx/TextValue.py +34 -0
- gedcomx/TopLevelTypeCollection.py +47 -0
- gedcomx/URI.py +70 -0
- gedcomx/_Resource.py +11 -0
- gedcomx/__init__.py +39 -0
gedcomx/GedcomX.py
ADDED
@@ -0,0 +1,1105 @@
|
|
1
|
+
DEBUG = False
|
2
|
+
import base64
|
3
|
+
import json
|
4
|
+
import mimetypes
|
5
|
+
import re
|
6
|
+
import uuid
|
7
|
+
import xml.etree.ElementTree as ET
|
8
|
+
|
9
|
+
from typing import List, Optional
|
10
|
+
from xml.dom import minidom
|
11
|
+
from .Address import Address
|
12
|
+
from .Agent import Agent
|
13
|
+
from .Attribution import Attribution
|
14
|
+
from .Conclusion import Conclusion
|
15
|
+
from .Coverage import Coverage
|
16
|
+
from .Date import Date
|
17
|
+
from .Document import Document
|
18
|
+
from .EvidenceReference import EvidenceReference
|
19
|
+
from .Event import Event,EventType,EventRole,EventRoleType
|
20
|
+
from .Fact import Fact, FactType, FactQualifier
|
21
|
+
from .Gedcom import Gedcom
|
22
|
+
from .Gedcom import GedcomRecord
|
23
|
+
from .Gender import Gender, GenderType
|
24
|
+
from .Group import Group
|
25
|
+
from .Identifier import Identifier, IdentifierType
|
26
|
+
from .Name import Name, NameType, NameForm, NamePart, NamePartType, NamePartQualifier
|
27
|
+
from .Note import Note
|
28
|
+
from .OnlineAccount import OnlineAccount
|
29
|
+
from .Person import Person
|
30
|
+
from .PlaceDescription import PlaceDescription
|
31
|
+
from .PlaceReference import PlaceReference
|
32
|
+
from .Qualifier import Qualifier
|
33
|
+
from .Relationship import Relationship, RelationshipType
|
34
|
+
from .SourceCitation import SourceCitation
|
35
|
+
from .SourceDescription import SourceDescription, ResourceType
|
36
|
+
from .SourceReference import SourceReference, KnownSourceReference
|
37
|
+
from .Subject import Subject
|
38
|
+
from .TextValue import TextValue
|
39
|
+
from .TopLevelTypeCollection import TopLevelTypeCollection
|
40
|
+
from .URI import URI
|
41
|
+
|
42
|
+
def TypeCollection(item_type):
|
43
|
+
class Collection:
|
44
|
+
def __init__(self):
|
45
|
+
self._items = []
|
46
|
+
self._id_index = {}
|
47
|
+
self._name_index = {}
|
48
|
+
self._uri_index = {}
|
49
|
+
self.uri = URI(path=f'/{item_type.__name__}s/')
|
50
|
+
|
51
|
+
def __iter__(self):
|
52
|
+
self._index = 0
|
53
|
+
return self
|
54
|
+
|
55
|
+
def __next__(self):
|
56
|
+
if self._index < len(self._items):
|
57
|
+
result = self._items[self._index]
|
58
|
+
self._index += 1
|
59
|
+
return result
|
60
|
+
else:
|
61
|
+
raise StopIteration
|
62
|
+
|
63
|
+
@property
|
64
|
+
def item_type(self):
|
65
|
+
return item_type
|
66
|
+
|
67
|
+
def _update_indexes(self, item):
|
68
|
+
# Update the id index
|
69
|
+
if hasattr(item, 'id'):
|
70
|
+
self._id_index[item.id] = item
|
71
|
+
|
72
|
+
try:
|
73
|
+
if hasattr(item, '_uri'):
|
74
|
+
self._uri_index[item._uri.value] = item
|
75
|
+
except AttributeError as e:
|
76
|
+
print(f"type{item}")
|
77
|
+
assert False
|
78
|
+
|
79
|
+
# Update the name index
|
80
|
+
''' #TODO Fix name handling on persons
|
81
|
+
if hasattr(item, 'names'):
|
82
|
+
names = getattr(item, 'names')
|
83
|
+
for name in names:
|
84
|
+
print(name._as_dict_)
|
85
|
+
name_value = name.value if isinstance(name, TextValue) else name
|
86
|
+
if name_value in self._name_index:
|
87
|
+
self._name_index[name_value].append(item)
|
88
|
+
else:
|
89
|
+
self._name_index[name_value] = [item]
|
90
|
+
'''
|
91
|
+
|
92
|
+
def _remove_from_indexes(self, item):
|
93
|
+
# Remove from the id index
|
94
|
+
if hasattr(item, 'id'):
|
95
|
+
if item.id in self._id_index:
|
96
|
+
del self._id_index[item.id]
|
97
|
+
|
98
|
+
# Remove from the name index
|
99
|
+
if hasattr(item, 'names'):
|
100
|
+
names = getattr(item, 'names')
|
101
|
+
for name in names:
|
102
|
+
name_value = name.value if isinstance(name, TextValue) else name
|
103
|
+
if name_value in self._name_index:
|
104
|
+
if item in self._name_index[name_value]:
|
105
|
+
self._name_index[name_value].remove(item)
|
106
|
+
if not self._name_index[name_value]:
|
107
|
+
del self._name_index[name_value]
|
108
|
+
|
109
|
+
def byName(self, sname: str):
|
110
|
+
# Use the name index for fast lookup
|
111
|
+
sname = sname.strip()
|
112
|
+
return self._name_index.get(sname, [])
|
113
|
+
|
114
|
+
def byId(self, id):
|
115
|
+
# Use the id index for fast lookup
|
116
|
+
return self._id_index.get(id, None)
|
117
|
+
|
118
|
+
def byUri(self, uri):
|
119
|
+
# Use the id index for fast lookup
|
120
|
+
return self._uri_index.get(uri.value, None)
|
121
|
+
|
122
|
+
def append(self, item):
|
123
|
+
if not isinstance(item, item_type):
|
124
|
+
raise TypeError(f"Expected item of type {item_type.__name__}, got {type(item).__name__}")
|
125
|
+
item._uri._path = f'{str(item_type.__name__)}s' if item._uri._path is None else item._uri._path
|
126
|
+
#if isinstance(item,Agent):
|
127
|
+
# item._uri._path = 'Agents'
|
128
|
+
# print(item._uri._as_dict_)
|
129
|
+
|
130
|
+
self._items.append(item)
|
131
|
+
self._update_indexes(item)
|
132
|
+
|
133
|
+
def remove(self, item):
|
134
|
+
if item not in self._items:
|
135
|
+
raise ValueError("Item not found in the collection.")
|
136
|
+
self._items.remove(item)
|
137
|
+
self._remove_from_indexes(item)
|
138
|
+
|
139
|
+
def __repr__(self):
|
140
|
+
return f"Collection({self._items!r})"
|
141
|
+
|
142
|
+
def list(self):
|
143
|
+
for item in self._items:
|
144
|
+
print(item)
|
145
|
+
|
146
|
+
def __call__(self, **kwargs):
|
147
|
+
results = []
|
148
|
+
for item in self._items:
|
149
|
+
match = True
|
150
|
+
for key, value in kwargs.items():
|
151
|
+
if not hasattr(item, key) or getattr(item, key) != value:
|
152
|
+
match = False
|
153
|
+
break
|
154
|
+
if match:
|
155
|
+
results.append(item)
|
156
|
+
return results
|
157
|
+
|
158
|
+
def __len__(self):
|
159
|
+
return len(self._items)
|
160
|
+
|
161
|
+
def __getitem__(self, index):
|
162
|
+
return self._items[index]
|
163
|
+
|
164
|
+
@property
|
165
|
+
def _items_as_dict(self) -> dict:
|
166
|
+
print(self.item_type)
|
167
|
+
|
168
|
+
#return {f'{str(item_type.__name__)}s': [item._as_dict_ for item in self._items]}
|
169
|
+
return {f'{str(item_type.__name__)}s': [item._as_dict_ for item in self._items]}
|
170
|
+
|
171
|
+
@property
|
172
|
+
def json(self):
|
173
|
+
return json.dumps(self._as_dict, indent=4)
|
174
|
+
|
175
|
+
@property
|
176
|
+
def _as_dict_(self):
|
177
|
+
return {"Collection": [item._as_dict_ for item in self._items]}
|
178
|
+
|
179
|
+
return Collection()
|
180
|
+
|
181
|
+
class GedcomX:
|
182
|
+
version = 'http://gedcomx.org/conceptual-model/v1'
|
183
|
+
|
184
|
+
def __init__(self, id: str = None, attribution: Attribution = None, filepath: str = None) -> None:
|
185
|
+
self.id = id
|
186
|
+
self.attribution = attribution
|
187
|
+
|
188
|
+
self._filepath = None
|
189
|
+
|
190
|
+
self.source_descriptions = TypeCollection(SourceDescription)
|
191
|
+
self.persons = TypeCollection(Person)
|
192
|
+
self.relationships = TypeCollection(Relationship)
|
193
|
+
self.agents = TypeCollection(Agent)
|
194
|
+
self.events = TypeCollection(Event)
|
195
|
+
self.documents = TypeCollection(Document)
|
196
|
+
self.places = TypeCollection(PlaceDescription)
|
197
|
+
self.groups = TypeCollection(Group)
|
198
|
+
|
199
|
+
self.person_relationships_lookup = {}
|
200
|
+
|
201
|
+
def _add(self,gedcomx_type_object):
|
202
|
+
#print(type(gedcomx_type_object))
|
203
|
+
if gedcomx_type_object:
|
204
|
+
if isinstance(gedcomx_type_object,Person):
|
205
|
+
self.add_person(gedcomx_type_object)
|
206
|
+
elif isinstance(gedcomx_type_object,SourceDescription):
|
207
|
+
self.add_source_description(gedcomx_type_object)
|
208
|
+
elif isinstance(gedcomx_type_object,Agent):
|
209
|
+
self.add_agent(gedcomx_type_object)
|
210
|
+
elif isinstance(gedcomx_type_object,PlaceDescription):
|
211
|
+
self.add_place_description(gedcomx_type_object)
|
212
|
+
elif isinstance(gedcomx_type_object,Event):
|
213
|
+
self.add_event(gedcomx_type_object)
|
214
|
+
elif isinstance(gedcomx_type_object,Relationship):
|
215
|
+
self.add_relationship(gedcomx_type_object)
|
216
|
+
else:
|
217
|
+
raise ValueError(f"I do not know how to add an Object of type {type(gedcomx_type_object)}")
|
218
|
+
else:
|
219
|
+
Warning("Tried to add a None type to the Geneology")
|
220
|
+
|
221
|
+
def add_source_description(self,sourceDescription: SourceDescription):
|
222
|
+
if sourceDescription and isinstance(sourceDescription,SourceDescription):
|
223
|
+
if sourceDescription.id is None:
|
224
|
+
sourceDescription.id =self.default_id_generator()
|
225
|
+
self.source_descriptions.append(item=sourceDescription)
|
226
|
+
self.lastSourceDescriptionAdded = sourceDescription
|
227
|
+
else:
|
228
|
+
raise ValueError(f"When adding a SourceDescription, value must be of type SourceDescription, type {type(sourceDescription)} was provided")
|
229
|
+
|
230
|
+
def add_person(self,person: Person):
|
231
|
+
if person and isinstance(person,Person):
|
232
|
+
if person.id is None:
|
233
|
+
person.id =self.personURIgenerator()
|
234
|
+
self.persons.append(item=person)
|
235
|
+
else:
|
236
|
+
raise ValueError()
|
237
|
+
|
238
|
+
def add_relationship(self,relationship: Relationship):
|
239
|
+
if relationship and isinstance(relationship,Relationship):
|
240
|
+
if isinstance(relationship.person1,URI) and isinstance(relationship.person2,URI):
|
241
|
+
print("Adding unresolved Relationship")
|
242
|
+
self.relationships.append(relationship)
|
243
|
+
return
|
244
|
+
|
245
|
+
if relationship.person1:
|
246
|
+
if relationship.person1.id is None:
|
247
|
+
relationship.person1.id = self.personURIgenerator()
|
248
|
+
if not self.persons.byId(relationship.person1.id):
|
249
|
+
self.persons.append(relationship.person1)
|
250
|
+
if relationship.person1.id not in self.person_relationships_lookup:
|
251
|
+
self.person_relationships_lookup[relationship.person1.id] = []
|
252
|
+
self.person_relationships_lookup[relationship.person1.id].append(relationship)
|
253
|
+
relationship.person1._add_relationship(relationship)
|
254
|
+
else:
|
255
|
+
raise ValueError
|
256
|
+
|
257
|
+
if relationship.person2:
|
258
|
+
if relationship.person2.id is None:
|
259
|
+
relationship.person2.id = self.personURIgenerator() #TODO
|
260
|
+
if not self.persons.byId(relationship.person2.id):
|
261
|
+
self.persons.append(relationship.person2)
|
262
|
+
if relationship.person2.id not in self.person_relationships_lookup:
|
263
|
+
self.person_relationships_lookup[relationship.person2.id] = []
|
264
|
+
self.person_relationships_lookup[relationship.person2.id].append(relationship)
|
265
|
+
relationship.person2._add_relationship(relationship)
|
266
|
+
else:
|
267
|
+
raise ValueError
|
268
|
+
|
269
|
+
self.relationships.append(relationship)
|
270
|
+
else:
|
271
|
+
raise ValueError()
|
272
|
+
|
273
|
+
def add_place_description(self,placeDescription: PlaceDescription):
|
274
|
+
if placeDescription and isinstance(placeDescription,PlaceDescription):
|
275
|
+
if placeDescription.id is None:
|
276
|
+
placeDescription.id = self.PlaceDescriptionURIGenerator()
|
277
|
+
self.places.append(placeDescription)
|
278
|
+
|
279
|
+
def add_agent(self,agent: Agent):
|
280
|
+
if agent and isinstance(agent,Agent):
|
281
|
+
if agent.id is None:
|
282
|
+
raise("Empty ID")
|
283
|
+
agent.id = Agent.default_id_generator()
|
284
|
+
if self.agents.byId(agent.id):
|
285
|
+
raise ValueError
|
286
|
+
print(f'Added Agent with id: {agent.id}')
|
287
|
+
self.agents.append(agent)
|
288
|
+
|
289
|
+
def add_event(self,event_to_add: Event):
|
290
|
+
if event_to_add and isinstance(event_to_add,Event):
|
291
|
+
for current_event in self.events:
|
292
|
+
if event_to_add == current_event:
|
293
|
+
return
|
294
|
+
self.events.append(event_to_add)
|
295
|
+
|
296
|
+
def person(self,id: str):
|
297
|
+
filtered = [person for person in self.persons if getattr(person, 'id') == id]
|
298
|
+
if filtered: return filtered[0]
|
299
|
+
return None
|
300
|
+
|
301
|
+
def source(self,id: str):
|
302
|
+
filtered = [source for source in self.source_descriptions if getattr(source, 'id') == id]
|
303
|
+
if filtered: return filtered[0]
|
304
|
+
return None
|
305
|
+
|
306
|
+
|
307
|
+
class Translater():
|
308
|
+
def __init__(self,gedcom) -> None:
|
309
|
+
self.handlers = {}
|
310
|
+
self.gedcom: Gedcom = gedcom if gedcom else None
|
311
|
+
self.gedcomx = GedcomX()
|
312
|
+
|
313
|
+
self.object_stack = []
|
314
|
+
self.object_map = {}
|
315
|
+
self.missing_handler_count = {}
|
316
|
+
|
317
|
+
self.translate()
|
318
|
+
|
319
|
+
gedcom_even_to_fact = {
|
320
|
+
# Person Fact Types
|
321
|
+
"ADOP": FactType.Adoption,
|
322
|
+
"CHR": FactType.AdultChristening,
|
323
|
+
"EVEN": FactType.Amnesty, # and other FactTypes with no direct GEDCOM tag
|
324
|
+
"BAPM": FactType.Baptism,
|
325
|
+
"BARM": FactType.BarMitzvah,
|
326
|
+
"BASM": FactType.BatMitzvah,
|
327
|
+
"BIRT": FactType.Birth,
|
328
|
+
"BIRT, CHR": FactType.Birth,
|
329
|
+
"BLES": FactType.Blessing,
|
330
|
+
"BURI": FactType.Burial,
|
331
|
+
"CAST": FactType.Caste,
|
332
|
+
"CENS": FactType.Census,
|
333
|
+
"CIRC": FactType.Circumcision,
|
334
|
+
"CONF": FactType.Confirmation,
|
335
|
+
"CREM": FactType.Cremation,
|
336
|
+
"DEAT": FactType.Death,
|
337
|
+
"EDUC": FactType.Education,
|
338
|
+
"EMIG": FactType.Emigration,
|
339
|
+
"FCOM": FactType.FirstCommunion,
|
340
|
+
"GRAD": FactType.Graduation,
|
341
|
+
"IMMI": FactType.Immigration,
|
342
|
+
"MIL": FactType.MilitaryService,
|
343
|
+
"NATI": FactType.Nationality,
|
344
|
+
"NATU": FactType.Naturalization,
|
345
|
+
"OCCU": FactType.Occupation,
|
346
|
+
"ORDN": FactType.Ordination,
|
347
|
+
"DSCR": FactType.PhysicalDescription,
|
348
|
+
"PROB": FactType.Probate,
|
349
|
+
"PROP": FactType.Property,
|
350
|
+
"RELI": FactType.Religion,
|
351
|
+
"RESI": FactType.Residence,
|
352
|
+
"WILL": FactType.Will,
|
353
|
+
|
354
|
+
# Couple Relationship Fact Types
|
355
|
+
"ANUL": FactType.Annulment,
|
356
|
+
"DIV": FactType.Divorce,
|
357
|
+
"DIVF": FactType.DivorceFiling,
|
358
|
+
"ENGA": FactType.Engagement,
|
359
|
+
"MARR": FactType.Marriage,
|
360
|
+
"MARB": FactType.MarriageBanns,
|
361
|
+
"MARC": FactType.MarriageContract,
|
362
|
+
"MARL": FactType.MarriageLicense,
|
363
|
+
"SEPA": FactType.Separation,
|
364
|
+
|
365
|
+
# Parent-Child Relationship Fact Types
|
366
|
+
# (Note: Only ADOPTION has a direct GEDCOM tag, others are under "EVEN")
|
367
|
+
"ADOP": FactType.AdoptiveParent
|
368
|
+
}
|
369
|
+
|
370
|
+
|
371
|
+
def clean_str(text: str) -> str:
|
372
|
+
# Regular expression to match HTML/XML tags
|
373
|
+
clean_text = re.sub(r'<[^>]+>', '', text)
|
374
|
+
|
375
|
+
return clean_text
|
376
|
+
|
377
|
+
def translate(self):
|
378
|
+
for repository in self.gedcom.repositories:
|
379
|
+
self.parse_record(repository)
|
380
|
+
print(f"Translated {len(self.gedcomx.agents)} 'REPO' records to Agents")
|
381
|
+
for source in self.gedcom.sources:
|
382
|
+
self.parse_record(source)
|
383
|
+
print(f"Translated {len(self.gedcomx.source_descriptions)} 'SOUR' records to SourceDescription")
|
384
|
+
|
385
|
+
for object in self.gedcom.objects:
|
386
|
+
self.parse_record(object)
|
387
|
+
print(f"Translated {len(self.gedcom.objects)} 'OBJE' records to SourceDescriptions")
|
388
|
+
|
389
|
+
for individual in self.gedcom.individuals:
|
390
|
+
self.parse_record(individual)
|
391
|
+
print(f"Translated {len(self.gedcomx.persons)} 'INDI' records to Persons")
|
392
|
+
|
393
|
+
for key in self.missing_handler_count:
|
394
|
+
print(f"{key}: {self.missing_handler_count[key]}")
|
395
|
+
|
396
|
+
|
397
|
+
|
398
|
+
fam_count = len(self.gedcom.families)
|
399
|
+
for family in self.gedcom.families:
|
400
|
+
self.handle_fam(family)
|
401
|
+
print(f"Translated {fam_count} 'FAM' records to {len(self.gedcomx.relationships)} Relationship")
|
402
|
+
|
403
|
+
print(f"Translated {len(self.gedcomx.events)} 'EVEN' records to Events")
|
404
|
+
|
405
|
+
def find_urls(sef,text: str):
|
406
|
+
# Regular expression pattern to match URLs
|
407
|
+
url_pattern = re.compile(r'https?://[^\s]+')
|
408
|
+
# Find all URLs using the pattern
|
409
|
+
urls = url_pattern.findall(text)
|
410
|
+
return urls
|
411
|
+
|
412
|
+
@property
|
413
|
+
def event_type_conversion_table(self):
|
414
|
+
return {'BIRT':EventType.BIRTH,
|
415
|
+
'OBIT':FactType.OBITUARY}
|
416
|
+
|
417
|
+
def parse_record(self,record: GedcomRecord):
|
418
|
+
|
419
|
+
if DEBUG: print(record.describe())
|
420
|
+
handler_name = 'handle_' + record.tag.lower()
|
421
|
+
|
422
|
+
if hasattr(self,handler_name):
|
423
|
+
|
424
|
+
handler = getattr(self,handler_name)
|
425
|
+
handler(record)
|
426
|
+
else:
|
427
|
+
if record.tag in self.missing_handler_count:
|
428
|
+
self.missing_handler_count[record.tag] += 1
|
429
|
+
else:
|
430
|
+
self.missing_handler_count[record.tag] = 1
|
431
|
+
if not record.tag.startswith("_"):
|
432
|
+
print(f"\033[1;31mCould not find handler for GEDCOM tag {record.tag}\n{record.describe()}\033[0m")
|
433
|
+
for sub_record in record.subRecords():
|
434
|
+
self.parse_record(sub_record)
|
435
|
+
|
436
|
+
def handle__apid(self, record):
|
437
|
+
if isinstance(self.object_map[record.level-1], SourceReference):
|
438
|
+
self.object_map[record.level-1]._description_object.add_identifier(Identifier(value=URI.from_url('APID://' + record.value)))
|
439
|
+
elif isinstance(self.object_map[record.level-1], SourceDescription):
|
440
|
+
self.object_map[record.level-1].add_identifier(Identifier(value=URI.from_url('APID://' + record.value)))
|
441
|
+
else:
|
442
|
+
raise ValueError(f"Could not handle '_APID' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
|
443
|
+
|
444
|
+
def handle__meta(self, record):
|
445
|
+
if isinstance(self.object_map[record.level-1], SourceDescription):
|
446
|
+
gxobject = Note(text=Translater.clean_str(record.value))
|
447
|
+
self.object_map[record.level-1].add_note(gxobject)
|
448
|
+
self.object_stack.append(gxobject)
|
449
|
+
self.object_map[record.level] = gxobject
|
450
|
+
else:
|
451
|
+
raise ValueError(f"Could not handle 'WWW' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
|
452
|
+
|
453
|
+
def handle__wlnk(self, record):
|
454
|
+
return self.handle_sour(record)
|
455
|
+
|
456
|
+
def handle_addr(self, record):
|
457
|
+
if isinstance(self.object_map[record.level-1], Agent):
|
458
|
+
# TODO CHeck if URL?
|
459
|
+
if Translater.clean_str(record.value):
|
460
|
+
gxobject = URI(value=Translater.clean_str(record.value))
|
461
|
+
else:
|
462
|
+
gxobject = Address()
|
463
|
+
self.object_map[record.level-1].address = gxobject
|
464
|
+
self.object_stack.append(gxobject)
|
465
|
+
self.object_map[record.level] = gxobject
|
466
|
+
else:
|
467
|
+
raise ValueError(f"I do not know how to handle an 'ADDR' tag for a {type(self.object_map[record.level-1])}")
|
468
|
+
|
469
|
+
def handle_adr1(self, record):
|
470
|
+
if isinstance(self.object_map[record.level-1], Address):
|
471
|
+
if Translater.clean_str(record.value):
|
472
|
+
self.object_map[record.level-1].street = Translater.clean_str(record.value)
|
473
|
+
|
474
|
+
else:
|
475
|
+
raise ValueError(f"I do not know how to handle an 'ADDR' tag for a {type(self.object_map[record.level-1])}")
|
476
|
+
|
477
|
+
def handle_adop(self, record):
|
478
|
+
if isinstance(self.object_map[record.level-1], Person):
|
479
|
+
gxobject = Fact(type=FactType.ADOPTION)
|
480
|
+
self.object_map[record.level-1].add_fact(gxobject)
|
481
|
+
|
482
|
+
self.object_stack.append(gxobject)
|
483
|
+
self.object_map[record.level] = gxobject
|
484
|
+
else:
|
485
|
+
print("Cannot translate 'BAPM")
|
486
|
+
assert False
|
487
|
+
|
488
|
+
def handle_auth(self, record):
|
489
|
+
if isinstance(self.object_map[record.level-1], SourceDescription):
|
490
|
+
if self.gedcomx.agents.byName(record.value):
|
491
|
+
gxobject = self.gedcomx.agents.byName(record.value)[0]
|
492
|
+
else:
|
493
|
+
gxobject = Agent(names=[TextValue(record.value)])
|
494
|
+
self.gedcomx.add_agent(gxobject)
|
495
|
+
|
496
|
+
self.object_map[record.level-1].author = gxobject
|
497
|
+
self.object_stack.append(gxobject)
|
498
|
+
self.object_map[record.level] = gxobject
|
499
|
+
else:
|
500
|
+
print("Cannot translate 'AUTH")
|
501
|
+
assert False
|
502
|
+
|
503
|
+
def handle_bapm(self, record):
|
504
|
+
if isinstance(self.object_map[record.level-1], Person):
|
505
|
+
gxobject = Fact(type=FactType.Baptism)
|
506
|
+
self.object_map[record.level-1].add_fact(gxobject)
|
507
|
+
|
508
|
+
self.object_stack.append(gxobject)
|
509
|
+
self.object_map[record.level] = gxobject
|
510
|
+
else:
|
511
|
+
print("Cannot translate 'BAPM")
|
512
|
+
assert False
|
513
|
+
|
514
|
+
def handle_birt(self, record):
|
515
|
+
if isinstance(self.object_map[record.level-1], Person):
|
516
|
+
#gxobject = Event(type=EventType.BIRTH, roles=[EventRole(person=self.object_map[record.level-1], type=EventRoleType.Principal)])
|
517
|
+
gxobject = Fact(type=FactType.Birth)
|
518
|
+
#self.gedcomx.add_event(gxobject)
|
519
|
+
self.object_map[record.level-1].add_fact(gxobject)
|
520
|
+
|
521
|
+
self.object_stack.append(gxobject)
|
522
|
+
self.object_map[record.level] = gxobject
|
523
|
+
else:
|
524
|
+
print("Cannot translate 'AUTH")
|
525
|
+
assert False
|
526
|
+
|
527
|
+
def handle_buri(self, record):
|
528
|
+
if isinstance(self.object_map[record.level-1], Person):
|
529
|
+
gxobject = Fact(type=FactType.Burial)
|
530
|
+
self.object_map[record.level-1].add_fact(gxobject)
|
531
|
+
|
532
|
+
self.object_stack.append(gxobject)
|
533
|
+
self.object_map[record.level] = gxobject
|
534
|
+
else:
|
535
|
+
print("Cannot translate 'BURI")
|
536
|
+
assert False
|
537
|
+
|
538
|
+
def handle_caln(self, record):
|
539
|
+
if isinstance(self.object_map[record.level-1], SourceReference):
|
540
|
+
self.object_map[record.level-1].description.add_identifier(Identifier(value=URI.from_url('Call Number:' + record.value)))
|
541
|
+
elif isinstance(self.object_map[record.level-1], SourceDescription):
|
542
|
+
self.object_map[record.level-1].add_identifier(Identifier(value=URI.from_url('Call Number:' + record.value)))
|
543
|
+
elif isinstance(self.object_map[record.level-1], Agent):
|
544
|
+
pass
|
545
|
+
# TODO Why is GEDCOM so shitty? A callnumber for a repository?
|
546
|
+
else:
|
547
|
+
raise ValueError(f"Could not handle 'CALN' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
|
548
|
+
|
549
|
+
def handle_chr(self, record):
|
550
|
+
if isinstance(self.object_map[record.level-1], Person):
|
551
|
+
gxobject = Fact(type=FactType.Christening)
|
552
|
+
self.object_map[record.level-1].add_fact(gxobject)
|
553
|
+
|
554
|
+
self.object_stack.append(gxobject)
|
555
|
+
self.object_map[record.level] = gxobject
|
556
|
+
else:
|
557
|
+
print("Cannot translate 'CHR")
|
558
|
+
assert False
|
559
|
+
|
560
|
+
def handle_city(self, record):
|
561
|
+
if isinstance(self.object_map[record.level-1], Address):
|
562
|
+
self.object_map[record.level-1].city = Translater.clean_str(record.value)
|
563
|
+
else:
|
564
|
+
raise ValueError(f"I do not know how to handle an 'CITY' tag for a {type(self.object_map[record.level-1])}")
|
565
|
+
|
566
|
+
def handle_conc(self, record):
|
567
|
+
if isinstance(self.object_map[record.level-1], Note):
|
568
|
+
gxobject = Translater.clean_str(str(record.value))
|
569
|
+
self.object_map[record.level-1].append(gxobject)
|
570
|
+
elif isinstance(self.object_map[record.level-1], Agent):
|
571
|
+
gxobject = str(record.value)
|
572
|
+
self.object_map[record.level-1]._append_to_name(gxobject)
|
573
|
+
elif isinstance(self.object_map[record.level-1], Qualifier):
|
574
|
+
gxobject = str(record.value)
|
575
|
+
self.object_map[record.level-2].append(gxobject)
|
576
|
+
elif isinstance(self.object_map[record.level-1], TextValue):
|
577
|
+
#gxobject = TextValue(value=Translater.clean_str(record.value))
|
578
|
+
self.object_map[record.level-1]._append_to_value(record.value)
|
579
|
+
elif isinstance(self.object_map[record.level-1], SourceReference):
|
580
|
+
self.object_map[record.level-1].append(record.value)
|
581
|
+
elif isinstance(self.object_map[record.level-1], Fact):
|
582
|
+
self.object_map[record.level-1].notes[0].text += record.value
|
583
|
+
|
584
|
+
else:
|
585
|
+
print(f"Cannot translate 'CONC', {self.object_map[record.level-1]}")
|
586
|
+
assert False
|
587
|
+
|
588
|
+
def handle_cont(self, record):
|
589
|
+
if isinstance(self.object_map[record.level-1], Note):
|
590
|
+
gxobject = str("\n" + record.value)
|
591
|
+
self.object_map[record.level-1].append(gxobject)
|
592
|
+
elif isinstance(self.object_map[record.level-1], Agent):
|
593
|
+
gxobject = str("\n" + record.value)
|
594
|
+
elif isinstance(self.object_map[record.level-1], Qualifier):
|
595
|
+
gxobject = str("\n" + record.value)
|
596
|
+
self.object_map[record.level-1].append(gxobject)
|
597
|
+
elif isinstance(self.object_map[record.level-1], TextValue):
|
598
|
+
#gxobject = TextValue(value="\n" + record.value)
|
599
|
+
self.object_map[record.level-1]._append_to_value(record.value)
|
600
|
+
elif isinstance(self.object_map[record.level-1], SourceReference):
|
601
|
+
self.object_map[record.level-1].append(record.value)
|
602
|
+
else:
|
603
|
+
print(f"Cannot translate 'CONT', {type(self.object_map[record.level-1])}")
|
604
|
+
assert False
|
605
|
+
|
606
|
+
def handle__crea(self, record):
|
607
|
+
if isinstance(self.object_map[record.level-1], SourceDescription):
|
608
|
+
self.object_map[record.level-1].created = Date(original=record.value)
|
609
|
+
else:
|
610
|
+
raise ValueError(f"Could not handle '_URL' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
|
611
|
+
|
612
|
+
def handle_ctry(self, record):
|
613
|
+
if isinstance(self.object_map[record.level-1], Address):
|
614
|
+
self.object_map[record.level-1].country = Translater.clean_str(record.value)
|
615
|
+
else:
|
616
|
+
raise ValueError(f"I do not know how to handle an 'CTRY' tag for a {type(self.object_map[record.level-1])}")
|
617
|
+
|
618
|
+
def handle_data(self, record: GedcomRecord) -> None:
|
619
|
+
if record.value != '':
|
620
|
+
assert False
|
621
|
+
self.object_map[record.level] = None
|
622
|
+
|
623
|
+
def handle_date(self, record: GedcomRecord):
|
624
|
+
if record.parent.tag == 'PUBL':
|
625
|
+
gxobject = Date(original=record.value)
|
626
|
+
self.object_map[0].published = gxobject
|
627
|
+
|
628
|
+
self.object_stack.append(gxobject)
|
629
|
+
self.object_map[record.level] = gxobject
|
630
|
+
elif isinstance(self.object_map[record.level-1], Event):
|
631
|
+
self.object_map[record.level-1].date = Date(original=record.value)
|
632
|
+
elif isinstance(self.object_map[record.level-1], Fact):
|
633
|
+
self.object_map[record.level-1].date = Date(original=record.value)
|
634
|
+
elif record.parent.tag == 'DATA' and isinstance(self.object_map[record.level-2], SourceReference):
|
635
|
+
gxobject = Note(text='Date: ' + record.value)
|
636
|
+
self.object_map[record.level-2]._description_object.add_note(gxobject)
|
637
|
+
self.object_stack.append(gxobject)
|
638
|
+
self.object_map[record.level] = gxobject
|
639
|
+
elif isinstance(self.object_map[record.level-1], SourceDescription):
|
640
|
+
|
641
|
+
self.object_map[record.level-1].ctreated = record.value #TODO String to timestamp
|
642
|
+
|
643
|
+
else:
|
644
|
+
print(f"Cannot translate 'DATE {type(self.object_map[record.level-1])}")
|
645
|
+
assert False
|
646
|
+
|
647
|
+
def handle_deat(self, record):
|
648
|
+
if isinstance(self.object_map[record.level-1], Person):
|
649
|
+
gxobject = Fact(type=FactType.Death)
|
650
|
+
self.object_map[record.level-1].add_fact(gxobject)
|
651
|
+
|
652
|
+
self.object_stack.append(gxobject)
|
653
|
+
self.object_map[record.level] = gxobject
|
654
|
+
else:
|
655
|
+
print("Cannot translate 'DEAT")
|
656
|
+
assert False
|
657
|
+
|
658
|
+
def handle_even(self, record: GedcomRecord):
|
659
|
+
# TODO If events in a @S, check if only 1 person matches?
|
660
|
+
if not record.value.strip() == '':
|
661
|
+
values = [value.strip() for value in record.value.split(",")]
|
662
|
+
for value in values:
|
663
|
+
if value in Translater.gedcom_even_to_fact.keys():
|
664
|
+
if isinstance(self.object_map[record.level-1], Person):
|
665
|
+
gxobject = Fact(type=Translater.gedcom_even_to_fact[value])
|
666
|
+
self.object_map[record.level-1].add_fact(gxobject)
|
667
|
+
|
668
|
+
self.object_stack.append(gxobject)
|
669
|
+
self.object_map[record.level] = gxobject
|
670
|
+
print(self.object_map)
|
671
|
+
else:
|
672
|
+
print(record.describe())
|
673
|
+
assert False
|
674
|
+
# TODO: Fix, this. making an event to cacth subtags, why are these fact tied to a source? GEDCOM is horrible
|
675
|
+
gxobject = Event(type=EventType.UNKNOWN)
|
676
|
+
self.object_stack.append(gxobject)
|
677
|
+
self.object_map[record.level] = gxobject
|
678
|
+
else:
|
679
|
+
|
680
|
+
|
681
|
+
print("This event does not look like a Fact")
|
682
|
+
|
683
|
+
else:
|
684
|
+
possible_fact = FactType.guess(record.subRecord('TYPE')[0].value)
|
685
|
+
if possible_fact:
|
686
|
+
gxobject = Fact(type=possible_fact)
|
687
|
+
self.object_map[record.level-1].add_fact(gxobject)
|
688
|
+
|
689
|
+
self.object_stack.append(gxobject)
|
690
|
+
self.object_map[record.level] = gxobject
|
691
|
+
return
|
692
|
+
elif EventType.guess(record.subRecord('TYPE')[0].value):
|
693
|
+
if isinstance(self.object_map[record.level-1], Person):
|
694
|
+
gxobject = Event(type=EventType.guess(record.subRecord('TYPE')[0].value), roles=[EventRole(person=self.object_map[record.level-1], type=EventRoleType.Principal)])
|
695
|
+
self.gedcomx.add_event(gxobject)
|
696
|
+
self.object_stack.append(gxobject)
|
697
|
+
self.object_map[record.level] = gxobject
|
698
|
+
return
|
699
|
+
else:
|
700
|
+
if isinstance(self.object_map[record.level-1], Person):
|
701
|
+
gxobject = Event(type=None, roles=[EventRole(person=self.object_map[record.level-1], type=EventRoleType.Principal)])
|
702
|
+
gxobject.add_note(Note(subject='Event', text=record.value))
|
703
|
+
self.gedcomx.add_event(gxobject)
|
704
|
+
self.object_stack.append(gxobject)
|
705
|
+
self.object_map[record.level] = gxobject
|
706
|
+
return
|
707
|
+
|
708
|
+
else:
|
709
|
+
assert False
|
710
|
+
|
711
|
+
def handle_fam(self, record: GedcomRecord) -> None:
|
712
|
+
if record.tag != 'FAM' or record.level != 0:
|
713
|
+
raise ValueError("Invalid record: Must be a level 0 FAM record")
|
714
|
+
|
715
|
+
husband, wife, children = None, None, []
|
716
|
+
|
717
|
+
husband_record = record.subRecords('HUSB')
|
718
|
+
if husband_record:
|
719
|
+
husband = self.gedcomx.person(husband_record[0].value.replace('@',''))
|
720
|
+
|
721
|
+
wife_record = record.subRecords('WIFE')
|
722
|
+
if wife_record:
|
723
|
+
wife = self.gedcomx.person(wife_record[0].value.replace('@',''))
|
724
|
+
|
725
|
+
children_records = record.subRecords('CHIL')
|
726
|
+
if children_records:
|
727
|
+
for child_record in children_records:
|
728
|
+
child = self.gedcomx.person(child_record.value.replace('@',''))
|
729
|
+
if child:
|
730
|
+
children.append(child)
|
731
|
+
|
732
|
+
if husband:
|
733
|
+
for child in children:
|
734
|
+
relationship = Relationship(person1=husband, person2=child, type=RelationshipType.ParentChild)
|
735
|
+
self.gedcomx.add_relationship(relationship)
|
736
|
+
if wife:
|
737
|
+
for child in children:
|
738
|
+
relationship = Relationship(person1=wife, person2=child, type=RelationshipType.ParentChild)
|
739
|
+
self.gedcomx.add_relationship(relationship)
|
740
|
+
if husband and wife:
|
741
|
+
relationship = Relationship(person1=husband, person2=wife, type=RelationshipType.Couple)
|
742
|
+
self.gedcomx.add_relationship(relationship)
|
743
|
+
|
744
|
+
def handle_famc(self, record: GedcomRecord) -> None:
|
745
|
+
return
|
746
|
+
|
747
|
+
def handle_fams(self, record: GedcomRecord) -> None:
|
748
|
+
return
|
749
|
+
|
750
|
+
def handle_file(self, record: GedcomRecord):
|
751
|
+
if record.value.strip() != '':
|
752
|
+
#raise ValueError(f"I did not expect the 'FILE' tag to have a value: {record.value}")
|
753
|
+
#TODO Handle files referenced here
|
754
|
+
...
|
755
|
+
elif isinstance(self.object_map[record.level-1], SourceDescription):
|
756
|
+
...
|
757
|
+
self.object_map[record.level-1].resourceType = ResourceType.DigitalArtifact
|
758
|
+
|
759
|
+
|
760
|
+
def handle_form(self, record: GedcomRecord):
|
761
|
+
if record.parent.tag == 'FILE' and isinstance(self.object_map[record.level-2], SourceDescription):
|
762
|
+
if record.value.strip() != '':
|
763
|
+
mime_type, _ = mimetypes.guess_type('placehold.' + record.value)
|
764
|
+
if mime_type:
|
765
|
+
self.object_map[record.level-2].mediaType = mime_type
|
766
|
+
else:
|
767
|
+
print(f"Could not determing mime type from {record.value}")
|
768
|
+
else:
|
769
|
+
raise ValueError(f"I do not know how to translate the 'FORM' tag with value '{record.value}' for a {type(self.object_map[record.level-1])}")
|
770
|
+
|
771
|
+
def handle_givn(self, record):
|
772
|
+
if isinstance(self.object_map[record.level-1], Name):
|
773
|
+
given_name = NamePart(value=record.value, type=NamePartType.Given)
|
774
|
+
self.object_map[record.level-1]._add_name_part(given_name)
|
775
|
+
else:
|
776
|
+
print(f"{record.describe()}, Cannot translate 'NAME', {self.object_map[record.level-1]}")
|
777
|
+
assert False
|
778
|
+
|
779
|
+
def handle_indi(self, record):
|
780
|
+
person = Person(id=record.xref.replace('@',''))
|
781
|
+
self.gedcomx.add_person(person)
|
782
|
+
self.object_stack.append(person)
|
783
|
+
self.object_map[record.level] = person
|
784
|
+
|
785
|
+
def handle_immi(self, record):
|
786
|
+
if isinstance(self.object_map[record.level-1], Person):
|
787
|
+
gxobject = Fact(type=FactType.Immigration)
|
788
|
+
self.object_map[record.level-1].add_fact(gxobject)
|
789
|
+
|
790
|
+
self.object_stack.append(gxobject)
|
791
|
+
self.object_map[record.level] = gxobject
|
792
|
+
else:
|
793
|
+
print("Cannot translate 'IMMI")
|
794
|
+
assert False
|
795
|
+
|
796
|
+
def handle_marr(self, record):
|
797
|
+
if isinstance(self.object_map[record.level-1], Person):
|
798
|
+
gxobject = Fact(type=FactType.Marriage)
|
799
|
+
self.object_map[record.level-1].add_fact(gxobject)
|
800
|
+
|
801
|
+
self.object_stack.append(gxobject)
|
802
|
+
self.object_map[record.level] = gxobject
|
803
|
+
else:
|
804
|
+
print("Cannot translate 'MARR")
|
805
|
+
assert False
|
806
|
+
|
807
|
+
def handle_name(self, record):
|
808
|
+
if isinstance(self.object_map[record.level-1], Person):
|
809
|
+
gxobject = Name.simple(record.value)
|
810
|
+
#gxobject = Name(nameForms=[NameForm(fullText=record.value)], type=NameType.BirthName)
|
811
|
+
self.object_map[record.level-1].add_name(gxobject)
|
812
|
+
|
813
|
+
self.object_stack.append(gxobject)
|
814
|
+
self.object_map[record.level] = gxobject
|
815
|
+
elif isinstance(self.object_map[record.level-1], Agent):
|
816
|
+
gxobject = TextValue(value=record.value)
|
817
|
+
self.object_map[record.level-1].add_name(gxobject)
|
818
|
+
else:
|
819
|
+
print(f"{record.describe()}, Cannot translate 'NAME', {self.object_map[record.level-1]}")
|
820
|
+
assert False
|
821
|
+
|
822
|
+
def handle_note(self, record):
|
823
|
+
if isinstance(self.object_map[record.level-1], SourceDescription):
|
824
|
+
gxobject = Note(text=Translater.clean_str(record.value))
|
825
|
+
self.object_map[record.level-1].add_note(gxobject)
|
826
|
+
|
827
|
+
self.object_stack.append(gxobject)
|
828
|
+
self.object_map[record.level] = gxobject
|
829
|
+
elif isinstance(self.object_map[record.level-1], SourceReference):
|
830
|
+
gxobject = Note(text=Translater.clean_str(record.value))
|
831
|
+
self.object_map[record.level-1]._description_object.add_note(gxobject)
|
832
|
+
|
833
|
+
self.object_stack.append(gxobject)
|
834
|
+
self.object_map[record.level] = gxobject
|
835
|
+
elif isinstance(self.object_map[record.level-1], Conclusion):
|
836
|
+
gxobject = Note(text=record.value)
|
837
|
+
self.object_map[record.level-1].add_note(gxobject)
|
838
|
+
|
839
|
+
self.object_stack.append(gxobject)
|
840
|
+
self.object_map[record.level] = gxobject
|
841
|
+
else:
|
842
|
+
raise ValueError(f"Could not handle 'NOTE' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
|
843
|
+
assert False
|
844
|
+
|
845
|
+
def handle_nsfx(self, record):
|
846
|
+
if isinstance(self.object_map[record.level-1], Name):
|
847
|
+
surname = NamePart(value=record.value, type=NamePartType.Suffix)
|
848
|
+
self.object_map[record.level-1]._add_name_part(surname)
|
849
|
+
else:
|
850
|
+
print(f"{record.describe()}, Cannot translate 'NSFX', {self.object_map[record.level-1]}")
|
851
|
+
assert False
|
852
|
+
|
853
|
+
def handle_occu(self, record):
|
854
|
+
if isinstance(self.object_map[record.level-1], Person):
|
855
|
+
gxobject = Fact(type=FactType.Occupation)
|
856
|
+
self.object_map[record.level-1].add_fact(gxobject)
|
857
|
+
|
858
|
+
self.object_stack.append(gxobject)
|
859
|
+
self.object_map[record.level] = gxobject
|
860
|
+
else:
|
861
|
+
print("Cannot translate 'OCCU")
|
862
|
+
assert False
|
863
|
+
|
864
|
+
def handle_obje(self, record: GedcomRecord):
|
865
|
+
self.handle_sour(record)
|
866
|
+
|
867
|
+
def handle_page(self, record):
|
868
|
+
if isinstance(self.object_map[record.level-1], SourceReference):
|
869
|
+
self.object_map[record.level-1].descriptionId = record.value
|
870
|
+
self.object_map[record.level-1].add_qualifier(KnownSourceReference.Page)
|
871
|
+
|
872
|
+
#self.object_stack.append(gxobject)
|
873
|
+
#self.object_map[record.level] = gxobject
|
874
|
+
self.object_map[record.level] = self.object_map[record.level-1]
|
875
|
+
else:
|
876
|
+
raise ValueError(f"Could not handle 'PAGE' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
|
877
|
+
|
878
|
+
def handle_plac(self, record):
|
879
|
+
if isinstance(self.object_map[record.level-1], Agent):
|
880
|
+
gxobject = Address(value=record.value)
|
881
|
+
self.object_map[record.level-1].add_address(gxobject)
|
882
|
+
|
883
|
+
self.object_stack.append(gxobject)
|
884
|
+
self.object_map[record.level] = gxobject
|
885
|
+
elif isinstance(self.object_map[record.level-1], Event):
|
886
|
+
if self.gedcomx.places.byName(record.value):
|
887
|
+
self.object_map[record.level-1].place = PlaceReference(original=record.value, descriptionRef=self.gedcomx.places.byName(record.value)[0])
|
888
|
+
else:
|
889
|
+
place_des = PlaceDescription(names=[TextValue(value=record.value)])
|
890
|
+
self.gedcomx.add_place_description(place_des)
|
891
|
+
self.object_map[record.level-1].place = PlaceReference(original=record.value, descriptionRef=place_des)
|
892
|
+
elif isinstance(self.object_map[record.level-1], Fact):
|
893
|
+
if self.gedcomx.places.byName(record.value):
|
894
|
+
self.object_map[record.level-1].place = PlaceReference(original=record.value, descriptionRef=self.gedcomx.places.byName(record.value)[0])
|
895
|
+
else:
|
896
|
+
place_des = PlaceDescription(names=[TextValue(value=record.value)])
|
897
|
+
self.gedcomx.add_place_description(place_des)
|
898
|
+
self.object_map[record.level-1].place = PlaceReference(original=record.value, descriptionRef=place_des)
|
899
|
+
elif isinstance(self.object_map[record.level-1], SourceDescription):
|
900
|
+
gxobject = Note(text='Place: ' + record.value)
|
901
|
+
self.object_map[record.level-1].add_note(gxobject)
|
902
|
+
self.object_stack.append(gxobject)
|
903
|
+
self.object_map[record.level] = gxobject
|
904
|
+
else:
|
905
|
+
print("Cannot translate 'PLACE")
|
906
|
+
assert False
|
907
|
+
|
908
|
+
def handle_post(self, record):
|
909
|
+
if isinstance(self.object_map[record.level-1], Address):
|
910
|
+
self.object_map[record.level-1].postalCode = Translater.clean_str(record.value)
|
911
|
+
else:
|
912
|
+
raise ValueError(f"I do not know how to handle an 'POST' tag for a {type(self.object_map[record.level-1])}")
|
913
|
+
|
914
|
+
def handle_publ(self, record):
|
915
|
+
if isinstance(self.object_map[record.level-1], SourceDescription):
|
916
|
+
if self.gedcomx.agents.byName(record.value):
|
917
|
+
gxobject = self.gedcomx.agents.byName(record.value)[0]
|
918
|
+
else:
|
919
|
+
gxobject = Agent(names=[TextValue(record.value)])
|
920
|
+
self.gedcomx.add_agent(gxobject)
|
921
|
+
self.object_map[record.level-1].publisher = gxobject
|
922
|
+
|
923
|
+
self.object_stack.append(gxobject)
|
924
|
+
self.object_map[record.level] = gxobject
|
925
|
+
else:
|
926
|
+
print("Cannot translate 'PUBL")
|
927
|
+
assert False
|
928
|
+
|
929
|
+
def handle_prob(self, record):
|
930
|
+
if isinstance(self.object_map[record.level-1], Person):
|
931
|
+
gxobject = Fact(type=FactType.Probate)
|
932
|
+
self.object_map[record.level-1].add_fact(gxobject)
|
933
|
+
|
934
|
+
self.object_stack.append(gxobject)
|
935
|
+
self.object_map[record.level] = gxobject
|
936
|
+
else:
|
937
|
+
print("Cannot translate 'PROB")
|
938
|
+
assert False
|
939
|
+
|
940
|
+
def handle_refn(self, record):
|
941
|
+
if isinstance(self.object_map[record.level-1], Person) or isinstance(self.object_map[record.level-1], SourceDescription):
|
942
|
+
self.object_map[record.level-1].add_identifier(Identifier(value=URI.from_url('Reference Number:' + record.value)))
|
943
|
+
else:
|
944
|
+
raise ValueError(f"Could not handle 'REFN' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
|
945
|
+
|
946
|
+
def handle_repo(self, record):
|
947
|
+
if record.level == 0:
|
948
|
+
|
949
|
+
gxobject = Agent(id=record.value.replace('@',''))
|
950
|
+
self.gedcomx.add_agent(gxobject)
|
951
|
+
self.object_stack.append(gxobject)
|
952
|
+
self.object_map[record.level] = gxobject
|
953
|
+
|
954
|
+
elif isinstance(self.object_map[record.level-1], SourceDescription):
|
955
|
+
if self.gedcomx.agents.byId(record.value.replace('@','')):
|
956
|
+
# TODO WHere and what to add this to?
|
957
|
+
gxobject = self.gedcomx.agents.byId(record.value)
|
958
|
+
self.object_map[record.level-1].repository = gxobject
|
959
|
+
else:
|
960
|
+
print(record.describe())
|
961
|
+
raise ValueError()
|
962
|
+
gxobject = Agent(names=[TextValue(record.value)])
|
963
|
+
else:
|
964
|
+
raise ValueError(f"I do not know how to handle 'REPO' tag that is not a top-level, or sub-tag of {type(self.object_map[record.level-1])}")
|
965
|
+
|
966
|
+
|
967
|
+
self.object_stack.append(gxobject)
|
968
|
+
self.object_map[record.level] = gxobject
|
969
|
+
|
970
|
+
def handle_resi(self, record):
|
971
|
+
if isinstance(self.object_map[record.level-1], Person):
|
972
|
+
gxobject = Fact(type=FactType.Residence)
|
973
|
+
if record.value.strip() != '':
|
974
|
+
gxobject.add_note(Note(text=record.value))
|
975
|
+
self.object_map[record.level-1].add_fact(gxobject)
|
976
|
+
|
977
|
+
self.object_stack.append(gxobject)
|
978
|
+
self.object_map[record.level] = gxobject
|
979
|
+
else:
|
980
|
+
print("Cannot translate 'RESI")
|
981
|
+
assert False
|
982
|
+
|
983
|
+
def handle_rin(self, record):
|
984
|
+
if isinstance(self.object_map[record.level-1], SourceDescription):
|
985
|
+
self.object_map[record.level-1].id = record.value
|
986
|
+
self.object_map[record.level-1].add_note(Note(text=f"Source had RIN: of {record.value}"))
|
987
|
+
|
988
|
+
else:
|
989
|
+
raise ValueError(f"Could not handle 'RIN' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
|
990
|
+
|
991
|
+
def handle_sex(self, record: GedcomRecord):
|
992
|
+
|
993
|
+
if isinstance(self.object_map[record.level-1], Person):
|
994
|
+
if record.value == 'M':
|
995
|
+
gxobject = Gender(type=GenderType.Male)
|
996
|
+
elif record.value == 'F':
|
997
|
+
gxobject = Gender(type=GenderType.Female)
|
998
|
+
else:
|
999
|
+
gxobject = Gender(type=GenderType.Unknown)
|
1000
|
+
self.object_map[record.level-1].gender = gxobject
|
1001
|
+
|
1002
|
+
self.object_stack.append(gxobject)
|
1003
|
+
self.object_map[record.level] = gxobject
|
1004
|
+
else:
|
1005
|
+
assert False
|
1006
|
+
|
1007
|
+
def handle_sour(self, record):
|
1008
|
+
if record.level == 0 or record.tag == '_WLNK' or (record.level == 0 and record.tag == 'OBJE'):
|
1009
|
+
source_description = SourceDescription(id=record.xref)
|
1010
|
+
self.gedcomx.add_source_description(source_description)
|
1011
|
+
self.object_stack.append(source_description)
|
1012
|
+
self.object_map[record.level] = source_description
|
1013
|
+
else:
|
1014
|
+
if self.gedcomx.source_descriptions.byId(record.xref):
|
1015
|
+
gxobject = SourceReference(descriptionId=record.xref, description=self.gedcomx.source_descriptions.byId(record.xref))
|
1016
|
+
else:
|
1017
|
+
source_description = SourceDescription(id=record.xref)
|
1018
|
+
gxobject = SourceReference(descriptionId=record.value, description=source_description)
|
1019
|
+
if isinstance(self.object_map[record.level-1],SourceReference):
|
1020
|
+
self.object_map[record.level-1]._description_object.add_source(gxobject)
|
1021
|
+
else:
|
1022
|
+
self.object_map[record.level-1].add_source(gxobject)
|
1023
|
+
self.object_stack.append(gxobject)
|
1024
|
+
self.object_map[record.level] = gxobject
|
1025
|
+
|
1026
|
+
|
1027
|
+
def handle_stae(self, record):
|
1028
|
+
if isinstance(self.object_map[record.level-1], Address):
|
1029
|
+
self.object_map[record.level-1].stateOrProvince = Translater.clean_str(record.value)
|
1030
|
+
else:
|
1031
|
+
raise ValueError(f"I do not know how to handle an 'STAE' tag for a {type(self.object_map[record.level-1])}")
|
1032
|
+
|
1033
|
+
def handle_surn(self, record):
|
1034
|
+
if isinstance(self.object_map[record.level-1], Name):
|
1035
|
+
surname = NamePart(value=record.value, type=NamePartType.Surname)
|
1036
|
+
self.object_map[record.level-1]._add_name_part(surname)
|
1037
|
+
else:
|
1038
|
+
print(f"{record.describe()}, Cannot translate 'NAME', {self.object_map[record.level-1]}")
|
1039
|
+
assert False
|
1040
|
+
|
1041
|
+
def handle_text(self, record: GedcomRecord):
|
1042
|
+
if record.parent.tag == 'DATA':
|
1043
|
+
if isinstance(self.object_map[record.level-2], SourceReference):
|
1044
|
+
gxobject = TextValue(value=record.value)
|
1045
|
+
self.object_map[record.level-2]._description_object.add_description(gxobject)
|
1046
|
+
self.object_stack.append(gxobject)
|
1047
|
+
self.object_map[record.level] = gxobject
|
1048
|
+
else:
|
1049
|
+
assert False
|
1050
|
+
|
1051
|
+
def handle_titl(self, record):
|
1052
|
+
if isinstance(self.object_map[record.level-1], SourceDescription):
|
1053
|
+
|
1054
|
+
gxobject = TextValue(value=Translater.clean_str(record.value))
|
1055
|
+
self.object_map[record.level-1].add_title(gxobject)
|
1056
|
+
|
1057
|
+
self.object_stack.append(gxobject)
|
1058
|
+
self.object_map[record.level] = gxobject
|
1059
|
+
|
1060
|
+
elif record.parent.tag == 'FILE' and isinstance(self.object_map[record.level-2], SourceDescription):
|
1061
|
+
gxobject = TextValue(value=record.value)
|
1062
|
+
self.object_map[record.level-2].add_title(gxobject)
|
1063
|
+
|
1064
|
+
self.object_stack.append(gxobject)
|
1065
|
+
self.object_map[record.level] = gxobject
|
1066
|
+
elif self.object_map[record.level] and isinstance(self.object_map[record.level], Name):
|
1067
|
+
gxobject = NamePart(value=record.value, qualifiers=[NamePartQualifier.Title])
|
1068
|
+
|
1069
|
+
self.object_map[record.level]._add_name_part(gxobject)
|
1070
|
+
else:
|
1071
|
+
print(self.object_map)
|
1072
|
+
print(self.object_map[record.level])
|
1073
|
+
raise ValueError(f"Could not handle 'TITL' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
|
1074
|
+
assert False
|
1075
|
+
|
1076
|
+
def handle_type(self, record):
|
1077
|
+
# peek to see if event or fact
|
1078
|
+
if isinstance(self.object_map[record.level-1], Event):
|
1079
|
+
if EventType.guess(record.value):
|
1080
|
+
self.object_map[record.level-1].type = EventType.guess(record.value)
|
1081
|
+
else:
|
1082
|
+
self.object_map[record.level-1].type = None
|
1083
|
+
self.object_map[record.level-1].add_note(Note(text=Translater.clean_str(record.value)))
|
1084
|
+
elif isinstance(self.object_map[record.level-1], Fact):
|
1085
|
+
if not self.object_map[record.level-1].type:
|
1086
|
+
self.object_map[0].type = FactType.guess(record.value)
|
1087
|
+
elif record.parent.tag == 'FORM':
|
1088
|
+
if not self.object_map[0].mediaType:
|
1089
|
+
self.object_map[0].mediaType = record.value
|
1090
|
+
|
1091
|
+
else:
|
1092
|
+
raise ValueError(f"I do not know how to handle 'TYPE' tag for {type(self.object_map[record.level-1])}")
|
1093
|
+
|
1094
|
+
def handle__url(self, record):
|
1095
|
+
if isinstance(self.object_map[record.level-2], SourceDescription):
|
1096
|
+
self.object_map[record.level-2].about = URI.from_url(record.value)
|
1097
|
+
else:
|
1098
|
+
raise ValueError(f"Could not handle '_URL' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
|
1099
|
+
|
1100
|
+
def handle_www(self, record):
|
1101
|
+
if isinstance(self.object_map[record.level-2], SourceReference):
|
1102
|
+
self.object_map[record.level-2]._description_object.add_identifier(Identifier(value=URI.from_url(record.value)))
|
1103
|
+
else:
|
1104
|
+
raise ValueError(f"Could not handle 'WWW' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
|
1105
|
+
|