gedcom-x 0.5.5__py3-none-any.whl → 0.5.7__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.
gedcomx/Converter.py ADDED
@@ -0,0 +1,1034 @@
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, Any
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, date_to_timestamp
17
+ from .Document import Document
18
+ from .EvidenceReference import EvidenceReference
19
+ from .Exceptions import TagConversionError
20
+ from .Event import Event,EventType,EventRole,EventRoleType
21
+ from .Fact import Fact, FactType, FactQualifier
22
+ from .Gedcom import Gedcom
23
+ from .Gedcom5x import Gedcom5x, Gedcom5xRecord
24
+ from .GedcomX import GedcomX
25
+ from .Gender import Gender, GenderType
26
+ from .Group import Group
27
+ from .Identifier import Identifier, IdentifierType, make_uid, IdentifierList
28
+ from .Logging import get_logger
29
+ from .Name import Name, NameType, NameForm, NamePart, NamePartType, NamePartQualifier
30
+ from .Note import Note
31
+ from .OnlineAccount import OnlineAccount
32
+ from .Person import Person
33
+ from .PlaceDescription import PlaceDescription
34
+ from .PlaceReference import PlaceReference
35
+ from .Qualifier import Qualifier
36
+ from .Relationship import Relationship, RelationshipType
37
+ from .SourceCitation import SourceCitation
38
+ from .SourceDescription import SourceDescription, ResourceType
39
+ from .SourceReference import SourceReference, KnownSourceReference
40
+ #from .Subject import Subject
41
+ from .TextValue import TextValue
42
+ from .TopLevelTypeCollection import TopLevelTypeCollection
43
+ from .Resource import Resource, URI
44
+
45
+
46
+ import logging
47
+ from .LoggingHub import hub, ChannelConfig
48
+ log = logging.getLogger("gedcomx")
49
+ job_id = "gedcomx.convert.GEDCOM5x"
50
+
51
+ class GedcomConverter():
52
+ def __init__(self) -> None:
53
+ self.gedcomx = GedcomX()
54
+ self.object_map: dict[Any, Any] = {-1:self.gedcomx}
55
+ self.missing_handler_count = {}
56
+
57
+ gedcom_even_to_fact = {
58
+ # Person Fact Types
59
+ "ADOP": FactType.Adoption,
60
+ "CHR": FactType.AdultChristening,
61
+ "EVEN": FactType.Amnesty, # and other FactTypes with no direct GEDCOM tag
62
+ "BAPM": FactType.Baptism,
63
+ "BARM": FactType.BarMitzvah,
64
+ "BASM": FactType.BatMitzvah,
65
+ "BIRT": FactType.Birth,
66
+ "BIRT, CHR": FactType.Birth,
67
+ "BLES": FactType.Blessing,
68
+ "BURI": FactType.Burial,
69
+ "CAST": FactType.Caste,
70
+ "CENS": FactType.Census,
71
+ "CIRC": FactType.Circumcision,
72
+ "CONF": FactType.Confirmation,
73
+ "CREM": FactType.Cremation,
74
+ "DEAT": FactType.Death,
75
+ "EDUC": FactType.Education,
76
+ "EMIG": FactType.Emigration,
77
+ "FCOM": FactType.FirstCommunion,
78
+ "GRAD": FactType.Graduation,
79
+ "IMMI": FactType.Immigration,
80
+ "MIL": FactType.MilitaryService,
81
+ "NATI": FactType.Nationality,
82
+ "NATU": FactType.Naturalization,
83
+ "OCCU": FactType.Occupation,
84
+ "ORDN": FactType.Ordination,
85
+ "DSCR": FactType.PhysicalDescription,
86
+ "PROB": FactType.Probate,
87
+ "PROP": FactType.Property,
88
+ "RELI": FactType.Religion,
89
+ "RESI": FactType.Residence,
90
+ "WILL": FactType.Will,
91
+
92
+ # Couple Relationship Fact Types
93
+ "ANUL": FactType.Annulment,
94
+ "DIV": FactType.Divorce,
95
+ "DIVF": FactType.DivorceFiling,
96
+ "ENGA": FactType.Engagement,
97
+ "MARR": FactType.Marriage,
98
+ "MARB": FactType.MarriageBanns,
99
+ "MARC": FactType.MarriageContract,
100
+ "MARL": FactType.MarriageLicense,
101
+ "SEPA": FactType.Separation,
102
+
103
+ # Parent-Child Relationship Fact Types
104
+ # (Note: Only ADOPTION has a direct GEDCOM tag, others are under "EVEN")
105
+ "ADOP": FactType.AdoptiveParent
106
+ }
107
+
108
+ gedcom_even_to_evnt = {
109
+ # Person Fact Types
110
+ "ADOP": EventType.Adoption,
111
+ "CHR": EventType.AdultChristening,
112
+ "BAPM": EventType.Baptism,
113
+ "BARM": EventType.BarMitzvah,
114
+ "BASM": EventType.BatMitzvah,
115
+ "BIRT": EventType.Birth,
116
+ "BIRT, CHR": EventType.Birth,
117
+ "BLES": EventType.Blessing,
118
+ "BURI": EventType.Burial,
119
+
120
+ "CENS": EventType.Census,
121
+ "CIRC": EventType.Circumcision,
122
+ "CONF": EventType.Confirmation,
123
+ "CREM": EventType.Cremation,
124
+ "DEAT": EventType.Death,
125
+ "EDUC": EventType.Education,
126
+ "EMIG": EventType.Emigration,
127
+ "FCOM": EventType.FirstCommunion,
128
+
129
+ "IMMI": EventType.Immigration,
130
+
131
+ "NATU": EventType.Naturalization,
132
+
133
+ "ORDN": EventType.Ordination,
134
+
135
+
136
+ # Couple Relationship Fact Types
137
+ "ANUL": EventType.Annulment,
138
+ "DIV": EventType.Divorce,
139
+ "DIVF": EventType.DivorceFiling,
140
+ "ENGA": EventType.Engagement,
141
+ "MARR": EventType.Marriage
142
+
143
+ }
144
+
145
+
146
+ def clean_str(self, text: str | None) -> str:
147
+ # Regular expression to match HTML/XML tags
148
+ if text is None or text.strip() == '':
149
+ return ""
150
+ clean_text = re.sub(r'<[^>]+>', '', text)
151
+
152
+ return clean_text
153
+
154
+ def parse_gedcom5x_recrod(self,record: Gedcom5xRecord):
155
+ if record:
156
+ with hub.use(job_id):
157
+ handler_name = 'handle_' + record.tag.lower()
158
+
159
+ if hasattr(self,handler_name):
160
+ log.info(f'Parsing Record: {record.describe()}')
161
+ handler = getattr(self,handler_name)
162
+ handler(record)
163
+ else:
164
+ if record.tag in self.missing_handler_count:
165
+ self.missing_handler_count[record.tag] += 1
166
+ else:
167
+ self.missing_handler_count[record.tag] = 1
168
+
169
+ log.error(f'Failed Parsing Record: {record.describe()}')
170
+ for sub_record in record.subRecords():
171
+ self.parse_gedcom5x_recrod(sub_record)
172
+
173
+ def handle__apid(self, record: Gedcom5xRecord):
174
+ if isinstance(self.object_map[record.level-1], SourceReference):
175
+ self.object_map[record.level-1].description.add_identifier(Identifier(value=[URI.from_url('APID://' + record.value if record.value else '')]))
176
+ elif isinstance(self.object_map[record.level-1], SourceDescription):
177
+ self.object_map[record.level-1].add_identifier(Identifier(value=[URI.from_url('APID://' + record.value if record.value else '')]))
178
+ else:
179
+ raise ValueError(f"Could not handle '_APID' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
180
+
181
+ def handle__meta(self, record: Gedcom5xRecord):
182
+ if isinstance(self.object_map[record.level-1], SourceDescription):
183
+ gxobject = Note(text=self.clean_str(record.value if record.value else 'Warning: This NOTE had not content.'))
184
+ self.object_map[record.level-1].add_note(gxobject)
185
+
186
+ self.object_map[record.level] = gxobject
187
+ else:
188
+ raise ValueError(f"Could not handle 'WWW' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
189
+
190
+ def handle__wlnk(self, record: Gedcom5xRecord):
191
+ return self.handle_sour(record)
192
+
193
+ def handle_addr(self, record: Gedcom5xRecord):
194
+ if isinstance(self.object_map[record.level-1], Agent):
195
+ # TODO CHeck if URL?
196
+ if record.value is not None and self.clean_str(record.value):
197
+ gxobject = Address(value=self.clean_str(record.value))
198
+ else:
199
+ gxobject = Address()
200
+ self.object_map[record.level-1].address = gxobject
201
+
202
+ self.object_map[record.level] = gxobject
203
+ else:
204
+ raise ValueError(f"I do not know how to handle an 'ADDR' tag for a {type(self.object_map[record.level-1])}")
205
+
206
+ def handle_adr1(self, record: Gedcom5xRecord):
207
+ if isinstance(self.object_map[record.level-1], Address):
208
+ if record.value is not None and self.clean_str(record.value):
209
+ self.object_map[record.level-1].street = self.clean_str(record.value)
210
+ else:
211
+ raise ValueError(f"I do not know how to handle an 'ADR1' tag for a {type(self.object_map[record.level-1])}")
212
+
213
+ def handle_adr2(self, record: Gedcom5xRecord):
214
+ if isinstance(self.object_map[record.level-1], Address):
215
+ if record.value is not None and self.clean_str(record.value):
216
+ self.object_map[record.level-1].street2 = self.clean_str(record.value)
217
+ else:
218
+ raise ValueError(f"I do not know how to handle an 'ADR2' tag for a {type(self.object_map[record.level-1])}")
219
+
220
+ def handle_adr3(self, record: Gedcom5xRecord):
221
+ if isinstance(self.object_map[record.level-1], Address):
222
+ if record.value is not None and self.clean_str(record.value):
223
+ self.object_map[record.level-1].street3 = self.clean_str(record.value)
224
+ else:
225
+ raise ValueError(f"I do not know how to handle an 'ADR3' tag for a {type(self.object_map[record.level-1])}")
226
+
227
+ def handle_adr4(self, record: Gedcom5xRecord):
228
+ if isinstance(self.object_map[record.level-1], Address):
229
+ if record.value is not None and self.clean_str(record.value):
230
+ self.object_map[record.level-1].street4 = self.clean_str(record.value)
231
+ else:
232
+ raise ValueError(f"I do not know how to handle an 'ADR4' tag for a {type(self.object_map[record.level-1])}")
233
+
234
+ def handle_adr5(self, record: Gedcom5xRecord):
235
+ if isinstance(self.object_map[record.level-1], Address):
236
+ if record.value is not None and self.clean_str(record.value):
237
+ self.object_map[record.level-1].street5 = self.clean_str(record.value)
238
+ else:
239
+ raise ValueError(f"I do not know how to handle an 'ADR5' tag for a {type(self.object_map[record.level-1])}")
240
+
241
+ def handle_adr6(self, record: Gedcom5xRecord):
242
+ if isinstance(self.object_map[record.level-1], Address):
243
+ if record.value is not None and self.clean_str(record.value):
244
+ self.object_map[record.level-1].street5 = self.clean_str(record.value)
245
+ else:
246
+ raise ValueError(f"I do not know how to handle an 'ADR6' tag for a {type(self.object_map[record.level-1])}")
247
+
248
+ def handle_phon(self, record: Gedcom5xRecord):
249
+ if isinstance(self.object_map[record.level-1], Agent):
250
+ if record.value is not None and self.clean_str(record.value):
251
+ self.object_map[record.level-1].phones.append(self.clean_str(record.value))
252
+ else:
253
+ raise ValueError(f"I do not know how to handle an '{record.tag}' tag for a {type(self.object_map[record.level-1])}")
254
+
255
+ def handle_email(self, record: Gedcom5xRecord):
256
+ if isinstance(self.object_map[record.level-1], Agent):
257
+ if record.value is not None and self.clean_str(record.value):
258
+ self.object_map[record.level-1].emails.append(self.clean_str(record.value))
259
+ else:
260
+ raise ValueError(f"I do not know how to handle an '{record.tag}' tag for a {type(self.object_map[record.level-1])}")
261
+
262
+ def handle_fax(self, record: Gedcom5xRecord):
263
+ if isinstance(self.object_map[record.level-1], Agent):
264
+ if record.value is not None and self.clean_str(record.value):
265
+ self.object_map[record.level-1].emails.append('FAX:' + (self.clean_str(record.value) if record.value is not None else ''))
266
+ else:
267
+ raise ValueError(f"I do not know how to handle an '{record.tag}' tag for a {type(self.object_map[record.level-1])}")
268
+
269
+ def handle_adop(self, record: Gedcom5xRecord):
270
+ if isinstance(self.object_map[record.level-1], Person):
271
+ gxobject = Fact(type=FactType.Adoption)
272
+ self.object_map[record.level-1].add_fact(gxobject)
273
+
274
+
275
+ self.object_map[record.level] = gxobject
276
+ else:
277
+ return #TODO
278
+ raise TagConversionError(record=record,levelstack=self.object_map)
279
+
280
+ def handle_auth(self, record: Gedcom5xRecord):
281
+ if isinstance(self.object_map[record.level-1], SourceDescription):
282
+ if record.value is not None and self.gedcomx.agents.byName(record.value):
283
+ gxobject = self.gedcomx.agents.byName(record.value)[0]
284
+ else:
285
+ gxobject = Agent(names=[TextValue(record.value)])
286
+ self.gedcomx.add_agent(gxobject)
287
+
288
+ self.object_map[record.level-1].author = gxobject
289
+
290
+ self.object_map[record.level] = gxobject
291
+ else:
292
+
293
+ raise TagConversionError(record=record,levelstack=self.object_map)
294
+
295
+ def handle_bapm(self, record: Gedcom5xRecord):
296
+ if isinstance(self.object_map[record.level-1], Person):
297
+ gxobject = Fact(type=FactType.Baptism)
298
+ self.object_map[record.level-1].add_fact(gxobject)
299
+
300
+
301
+ self.object_map[record.level] = gxobject
302
+ else:
303
+ raise TagConversionError(record=record,levelstack=self.object_map)
304
+
305
+ def handle_birt(self, record: Gedcom5xRecord):
306
+ if isinstance(self.object_map[record.level-1], Person):
307
+ gxobject = Fact(type=FactType.Birth)
308
+ self.object_map[record.level-1].add_fact(gxobject)
309
+ self.object_map[record.level] = gxobject
310
+ else:
311
+ raise TagConversionError(record=record,levelstack=self.object_map)
312
+
313
+ def handle_buri(self, record: Gedcom5xRecord):
314
+ if isinstance(self.object_map[record.level-1], Person):
315
+ gxobject = Fact(type=FactType.Burial)
316
+ self.object_map[record.level-1].add_fact(gxobject)
317
+
318
+
319
+ self.object_map[record.level] = gxobject
320
+ else:
321
+ raise TagConversionError(record=record,levelstack=self.object_map)
322
+
323
+ def handle_caln(self, record: Gedcom5xRecord):
324
+ if isinstance(self.object_map[record.level-1], SourceReference):
325
+ self.object_map[record.level-1].description.add_identifier(Identifier(value=[URI.from_url('Call Number:' + record.value if record.value else '')]))
326
+ elif isinstance(self.object_map[record.level-1], SourceDescription):
327
+ self.object_map[record.level-1].add_identifier(Identifier(value=[URI.from_url('Call Number:' + record.value if record.value else '')]))
328
+ elif isinstance(self.object_map[record.level-1], Agent):
329
+ pass
330
+ # TODO Why is GEDCOM so shitty? A callnumber for a repository?
331
+ else:
332
+ raise ValueError(f"Could not handle 'CALN' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
333
+
334
+ def handle_chan(self, record: Gedcom5xRecord):
335
+ if isinstance(self.object_map[record.level-1], SourceDescription):
336
+ date = record.subRecord('DATE')
337
+ if date is not None:
338
+ self.object_map[record.level-1].created = Date(date[0].value)
339
+ elif isinstance(self.object_map[record.level-1], Agent):
340
+ if self.object_map[record.level-1].attribution is None:
341
+ gxobject = Attribution()
342
+ self.object_map[record.level-1].attribution = gxobject
343
+ self.object_map[record.level] = gxobject
344
+ elif isinstance(self.object_map[record.level-1], Person):
345
+ if self.object_map[record.level-1].attribution is None:
346
+ gxobject = Attribution()
347
+ self.object_map[record.level-1].attribution = gxobject
348
+ self.object_map[record.level] = gxobject
349
+ else:
350
+ raise TagConversionError(record=record,levelstack=self.object_map)
351
+
352
+ def handle_chr(self, record: Gedcom5xRecord):
353
+ if isinstance(self.object_map[record.level-1], Person):
354
+ gxobject = Fact(type=FactType.Christening)
355
+ self.object_map[record.level-1].add_fact(gxobject)
356
+
357
+
358
+ self.object_map[record.level] = gxobject
359
+ else:
360
+ raise TagConversionError(record=record,levelstack=self.object_map)
361
+
362
+ def handle_city(self, record: Gedcom5xRecord):
363
+ if isinstance(self.object_map[record.level-1], Address):
364
+ if record.value is not None:
365
+ self.object_map[record.level-1].city = self.clean_str(record.value)
366
+ else: raise ValueError('Record had no value')
367
+ else:
368
+ raise ValueError(f"I do not know how to handle an 'CITY' tag for a {type(self.object_map[record.level-1])}")
369
+
370
+ def handle_conc(self, record: Gedcom5xRecord):
371
+ if isinstance(self.object_map[record.level-1], Note):
372
+ gxobject = self.clean_str(str(record.value))
373
+ self.object_map[record.level-1].append(gxobject)
374
+ elif isinstance(self.object_map[record.level-1], Agent):
375
+ gxobject = str(record.value)
376
+ self.object_map[record.level-1]._append_to_name(gxobject)
377
+ elif isinstance(self.object_map[record.level-1], Qualifier):
378
+ gxobject = str(record.value)
379
+ self.object_map[record.level-2].append(gxobject)
380
+ elif isinstance(self.object_map[record.level-1], TextValue):
381
+ #gxobject = TextValue(value=self.clean_str(record.value))
382
+ self.object_map[record.level-1]._append_to_value(record.value)
383
+ elif isinstance(self.object_map[record.level-1], SourceReference):
384
+ self.object_map[record.level-1].append(record.value)
385
+ elif isinstance(self.object_map[record.level-1], Fact):
386
+ self.object_map[record.level-1].notes[0].text += record.value
387
+
388
+ else:
389
+ raise TagConversionError(record=record,levelstack=self.object_map)
390
+
391
+ def handle_cont(self, record: Gedcom5xRecord):
392
+ if isinstance(self.object_map[record.level-1], Note):
393
+ gxobject = str("\n" + record.value if record.value else '')
394
+ self.object_map[record.level-1].append(gxobject)
395
+ elif isinstance(self.object_map[record.level-1], Agent):
396
+ gxobject = str("\n" + record.value if record.value else '')
397
+ elif isinstance(self.object_map[record.level-1], Qualifier):
398
+ gxobject = str("\n" + record.value if record.value else '')
399
+ self.object_map[record.level-1].append(gxobject)
400
+ elif isinstance(self.object_map[record.level-1], TextValue):
401
+ #gxobject = TextValue(value="\n" + record.value)
402
+ self.object_map[record.level-1]._append_to_value(record.value if record.value else '\n')
403
+ elif isinstance(self.object_map[record.level-1], SourceReference):
404
+ self.object_map[record.level-1].append(record.value)
405
+ elif isinstance(self.object_map[record.level-1], Address):
406
+ self.object_map[record.level-1]._append(record.value)
407
+ else:
408
+ raise TagConversionError(record=record,levelstack=self.object_map)
409
+
410
+ def handle_crea(self, record: Gedcom5xRecord):
411
+ if isinstance(self.object_map[record.level-1], SourceDescription):
412
+ date = record.subRecord('DATE')
413
+ if date is not None and date != []:
414
+ self.object_map[record.level-1].created = Date(original=date[0].value)
415
+ else: raise ValueError('DATE had not value')
416
+
417
+ elif isinstance(self.object_map[record.level-1], Agent):
418
+ if self.object_map[record.level-1].attribution is None:
419
+ gxobject = Attribution()
420
+ self.object_map[record.level-1].attribution = gxobject
421
+
422
+ self.object_map[record.level] = gxobject
423
+ else:
424
+ log.info(f"[{record.tag}] Attribution already exists for SourceDescription with id: {self.object_map[record.level-1].id}")
425
+ else:
426
+ raise ValueError(f"Could not handle '{record.tag}' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
427
+
428
+ def handle_ctry(self, record: Gedcom5xRecord):
429
+ if isinstance(self.object_map[record.level-1], Address):
430
+ if record.value is not None:
431
+ self.object_map[record.level-1].country = self.clean_str(record.value)
432
+ else:
433
+ raise ValueError('Recrod had no value')
434
+ else:
435
+ raise ValueError(f"I do not know how to handle an '{record.tag}' tag for a {type(self.object_map[record.level-1])}")
436
+
437
+ def handle_data(self, record: Gedcom5xRecord) -> None:
438
+ if record.value != '' and record.value == 'None':
439
+ assert False
440
+ self.object_map[record.level] = self.object_map[record.level-1]
441
+
442
+ def handle_date(self, record: Gedcom5xRecord):
443
+ if record.parent is not None and record.parent.tag == 'PUBL':
444
+ #gxobject = Date(original=record.value) #TODO Make a parser for solid timestamps
445
+ #self.object_map[0].published = gxobject
446
+ #self.object_map[0].published = date_to_timestamp(record.value) if record.value else None
447
+ self.object_map[0].published = record.value
448
+ #
449
+ #self.object_map[record.level] = gxobject
450
+ elif isinstance(self.object_map[record.level-1], Event):
451
+ self.object_map[record.level-1].date = Date(original=record.value)
452
+ elif isinstance(self.object_map[record.level-1], Fact):
453
+ self.object_map[record.level-1].date = Date(original=record.value)
454
+ elif record.parent is not None and record.parent.tag == 'DATA' and isinstance(self.object_map[record.level-2], SourceReference):
455
+ gxobject = Note(text='Date: ' + record.value if record.value else '')
456
+ self.object_map[record.level-2].description.add_note(gxobject)
457
+
458
+ self.object_map[record.level] = gxobject
459
+ elif isinstance(self.object_map[record.level-1], SourceDescription):
460
+
461
+ self.object_map[record.level-1].ctreated = record.value #TODO String to timestamp
462
+ elif isinstance(self.object_map[record.level-1], Attribution):
463
+ if record.parent is not None and record.parent.tag == 'CREA':
464
+ self.object_map[record.level-1].created = record.value #TODO G7
465
+ elif record.parent is not None and record.parent.tag == "CHAN":
466
+ self.object_map[record.level-1].modified = record.value #TODO G7
467
+ elif record.parent is not None and record.parent.tag in ['CREA','CHAN']:
468
+ pass
469
+
470
+ else:
471
+ raise TagConversionError(record=record,levelstack=self.object_map)
472
+
473
+ def handle_deat(self, record: Gedcom5xRecord):
474
+ if isinstance(self.object_map[record.level-1], Person):
475
+ gxobject = Fact(type=FactType.Death)
476
+ self.object_map[record.level-1].add_fact(gxobject)
477
+
478
+
479
+ self.object_map[record.level] = gxobject
480
+ else:
481
+ raise TagConversionError(record=record,levelstack=self.object_map)
482
+
483
+ def handle_even(self, record: Gedcom5xRecord):
484
+ # TODO If events in a @S, check if only 1 person matches?
485
+ if record.value and (not record.value.strip() == ''):
486
+ values = [value.strip() for value in record.value.split(",")]
487
+ for value in values:
488
+ if value in self.gedcom_even_to_fact.keys():
489
+ if isinstance(self.object_map[record.level-1], Person):
490
+ gxobject = Fact(type=self.gedcom_even_to_fact[value])
491
+ self.object_map[record.level-1].add_fact(gxobject)
492
+
493
+
494
+ self.object_map[record.level] = gxobject
495
+
496
+ elif isinstance(self.object_map[record.level-1], SourceDescription):
497
+ gxobject = Event(type=self.gedcom_even_to_evnt[value],sources=[self.object_map[record.level-1]])
498
+ self.gedcomx.add_event(gxobject)
499
+
500
+ self.object_map[record.level] = gxobject
501
+ else:
502
+ log.warning(f"Could not convert EVEN '{value}' for object of type {type(self.object_map[record.level-1])} in record {record.describe()}")
503
+ return
504
+ raise TagConversionError(record=record,levelstack=self.object_map)
505
+ assert False
506
+ # TODO: Fix, this. making an event to cacth subtags, why are these fact tied to a source? GEDCOM is horrible
507
+ gxobject = Event(type=EventType.UNKNOWN)
508
+
509
+ self.object_map[record.level] = gxobject
510
+ else:
511
+ raise TagConversionError(record=record,levelstack=self.object_map)
512
+
513
+ else:
514
+ possible_fact = FactType.guess(record.subRecord('TYPE')[0].value)
515
+ if possible_fact:
516
+ gxobject = Fact(type=possible_fact)
517
+ self.object_map[record.level-1].add_fact(gxobject)
518
+
519
+
520
+ self.object_map[record.level] = gxobject
521
+ return
522
+ elif EventType.guess(record.subRecord('TYPE')[0].value):
523
+ if isinstance(self.object_map[record.level-1], Person):
524
+ gxobject = Event(type=EventType.guess(record.subRecord('TYPE')[0].value), roles=[EventRole(person=self.object_map[record.level-1], type=EventRoleType.Principal)])
525
+ self.gedcomx.add_event(gxobject)
526
+
527
+ self.object_map[record.level] = gxobject
528
+ return
529
+ else:
530
+ if isinstance(self.object_map[record.level-1], Person):
531
+ gxobject = Event(type=None, roles=[EventRole(person=self.object_map[record.level-1], type=EventRoleType.Principal)])
532
+ gxobject.add_note(Note(subject='Event', text=record.value))
533
+ self.gedcomx.add_event(gxobject)
534
+
535
+ self.object_map[record.level] = gxobject
536
+ return
537
+
538
+ else:
539
+ assert False
540
+
541
+ def handle_exid(self,record: Gedcom5xRecord):
542
+ if record.value:
543
+ gxobject = Identifier(type=IdentifierType.External,value=[URI(record.value) if record.value else URI()]) # type: ignore
544
+ self.object_map[record.level-1].add_identifier(gxobject)
545
+ self.object_map[record.level] = gxobject
546
+ else: raise ValueError('Record had no value')
547
+
548
+ def handle_fam(self, record: Gedcom5xRecord) -> None:
549
+ if record.tag != 'FAM' or record.level != 0:
550
+ raise ValueError("Invalid record: Must be a level 0 FAM record")
551
+
552
+ husband, wife, children = None, None, []
553
+
554
+ husband_record = record.subRecords('HUSB')
555
+ if husband_record is not None:
556
+ id = husband_record[0].xref if len(husband_record) > 0 else None
557
+ if id:
558
+ husband = self.gedcomx.get_person_by_id(id)
559
+
560
+ wife_record = record.subRecords('WIFE')
561
+ if wife_record:
562
+ id = wife_record[0].xref if len(wife_record) > 0 else None
563
+ if id:
564
+ wife = self.gedcomx.get_person_by_id(id)
565
+
566
+ children_records = record.subRecords('CHIL')
567
+ if children_records:
568
+ for child_record in children_records:
569
+ id = child_record.xref
570
+ if id:
571
+ child = self.gedcomx.get_person_by_id(id)
572
+ if child:
573
+ children.append(child)
574
+
575
+ if husband:
576
+ for child in children:
577
+ relationship = Relationship(person1=husband, person2=child, type=RelationshipType.ParentChild)
578
+ self.gedcomx.add_relationship(relationship)
579
+ if wife:
580
+ for child in children:
581
+ relationship = Relationship(person1=wife, person2=child, type=RelationshipType.ParentChild)
582
+ self.gedcomx.add_relationship(relationship)
583
+ if husband and wife:
584
+ relationship = Relationship(person1=husband, person2=wife, type=RelationshipType.Couple)
585
+ self.gedcomx.add_relationship(relationship)
586
+
587
+ def handle_famc(self, record: Gedcom5xRecord) -> None:
588
+ return
589
+
590
+ def handle_fams(self, record: Gedcom5xRecord) -> None:
591
+ return
592
+
593
+ def handle_file(self, record: Gedcom5xRecord):
594
+ if record.value and record.value.strip() != '':
595
+ #raise ValueError(f"I did not expect the 'FILE' tag to have a value: {record.value}")
596
+ #TODO Handle files referenced here
597
+ ...
598
+ elif isinstance(self.object_map[record.level-1], SourceDescription):
599
+ ...
600
+ self.object_map[record.level-1].resourceType = ResourceType.DigitalArtifact
601
+
602
+ def handle_form(self, record: Gedcom5xRecord):
603
+ if record.parent is not None and record.parent.tag == 'FILE' and isinstance(self.object_map[record.level-2], SourceDescription):
604
+ if record.value and record.value.strip() != '':
605
+ mime_type, _ = mimetypes.guess_type('placehold.' + record.value)
606
+ if mime_type:
607
+ self.object_map[record.level-2].mediaType = mime_type
608
+ else:
609
+ print(f"Could not determing mime type from {record.value}")
610
+ elif isinstance(self.object_map[record.level-1], PlaceDescription):
611
+ self.object_map[record.level-1].names.append(TextValue(value=record.value))
612
+ elif record.parent is not None and record.parent.tag == 'TRAN':
613
+ pass #TODO
614
+ else:
615
+ log.error(f"raise TagConversionError(record=record,levelstack=self.object_map")
616
+
617
+ def handle_givn(self, record: Gedcom5xRecord):
618
+ if isinstance(self.object_map[record.level-1], Name):
619
+ given_name = NamePart(value=record.value, type=NamePartType.Given)
620
+ self.object_map[record.level-1]._add_name_part(given_name)
621
+ else:
622
+ raise TagConversionError(record=record,levelstack=self.object_map)
623
+
624
+ def handle_indi(self, record: Gedcom5xRecord):
625
+ person = self.gedcomx.persons.byId(record.xref)
626
+ if person is None:
627
+ log.warning('Had to create person with id {recrod.xref}')
628
+ if isinstance(record.xref,str):
629
+ person = Person(id=record.xref.replace('@',''))
630
+ else:
631
+ raise ValueError('INDI Record had no XREF')
632
+ self.gedcomx.add_person(person)
633
+ self.object_map[record.level] = person
634
+
635
+ def handle_immi(self, record: Gedcom5xRecord):
636
+ if isinstance(self.object_map[record.level-1], Person):
637
+ gxobject = Fact(type=FactType.Immigration)
638
+ self.object_map[record.level-1].add_fact(gxobject)
639
+
640
+
641
+ self.object_map[record.level] = gxobject
642
+ else:
643
+ raise TagConversionError(record=record,levelstack=self.object_map)
644
+
645
+ def handle_marr(self, record: Gedcom5xRecord):
646
+ if isinstance(self.object_map[record.level-1], Person):
647
+ gxobject = Fact(type=FactType.Marriage)
648
+ self.object_map[record.level-1].add_fact(gxobject)
649
+
650
+
651
+ self.object_map[record.level] = gxobject
652
+ else:
653
+ raise TagConversionError(record=record,levelstack=self.object_map)
654
+
655
+ def handle_name(self, record: Gedcom5xRecord):
656
+ if isinstance(self.object_map[record.level-1], Person):
657
+ gxobject = Name.simple(record.value if record.value else 'WARNING: NAME had no value')
658
+ #gxobject = Name(nameForms=[NameForm(fullText=record.value)], type=NameType.BirthName)
659
+ self.object_map[record.level-1].add_name(gxobject)
660
+
661
+
662
+ self.object_map[record.level] = gxobject
663
+ elif isinstance(self.object_map[record.level-1], Agent):
664
+ gxobject = TextValue(value=record.value)
665
+ self.object_map[record.level-1].add_name(gxobject)
666
+ else:
667
+ raise TagConversionError(record=record,levelstack=self.object_map)
668
+
669
+ def handle_note(self, record: Gedcom5xRecord):
670
+ if isinstance(self.object_map[record.level-1], SourceDescription):
671
+ gxobject = Note(text=self.clean_str(record.value))
672
+ self.object_map[record.level-1].add_note(gxobject)
673
+
674
+
675
+ self.object_map[record.level] = gxobject
676
+ elif isinstance(self.object_map[record.level-1], SourceReference):
677
+ gxobject = Note(text=self.clean_str(record.value))
678
+ self.object_map[record.level-1].description.add_note(gxobject)
679
+
680
+
681
+ self.object_map[record.level] = gxobject
682
+ elif isinstance(self.object_map[record.level-1], Conclusion):
683
+ gxobject = Note(text=record.value)
684
+ self.object_map[record.level-1].add_note(gxobject)
685
+
686
+
687
+ self.object_map[record.level] = gxobject
688
+ elif isinstance(self.object_map[record.level-1], Agent):
689
+ gxobject = Note(text=record.value)
690
+ self.object_map[record.level-1].add_note(gxobject)
691
+
692
+
693
+ self.object_map[record.level] = gxobject
694
+ elif isinstance(self.object_map[record.level-1], Attribution):
695
+ if self.object_map[record.level-1].changeMessage is None:
696
+ self.object_map[record.level-1].changeMessage = record.value
697
+ else:
698
+ self.object_map[record.level-1].changeMessage = self.object_map[record.level-1].changeMessage + '' + record.value
699
+ elif isinstance(self.object_map[record.level-1], Note):
700
+ gxobject = Note(text=self.clean_str(record.value))
701
+ self.object_map[record.level-2].add_note(gxobject)
702
+
703
+
704
+ self.object_map[record.level] = gxobject
705
+
706
+ else:
707
+ raise ValueError(f"Could not handle 'NOTE' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
708
+ assert False
709
+
710
+ def handle_nsfx(self, record: Gedcom5xRecord):
711
+ if isinstance(self.object_map[record.level-1], Name):
712
+ surname = NamePart(value=record.value, type=NamePartType.Suffix)
713
+ self.object_map[record.level-1]._add_name_part(surname)
714
+ else:
715
+ raise TagConversionError(record=record,levelstack=self.object_map)
716
+
717
+ def handle_occu(self, record: Gedcom5xRecord):
718
+ if isinstance(self.object_map[record.level-1], Person):
719
+ gxobject = Fact(type=FactType.Occupation)
720
+ self.object_map[record.level-1].add_fact(gxobject)
721
+
722
+
723
+ self.object_map[record.level] = gxobject
724
+ else:
725
+ raise TagConversionError(record=record,levelstack=self.object_map)
726
+
727
+ def handle_obje(self, record: Gedcom5xRecord):
728
+ self.handle_sour(record)
729
+
730
+ def handle_page(self, record: Gedcom5xRecord):
731
+ if isinstance(self.object_map[record.level-1], SourceReference):
732
+ self.object_map[record.level-1].descriptionId = record.value
733
+ gx_object = KnownSourceReference(name=KnownSourceReference.Page,value=record.value)
734
+ self.object_map[record.level-1].add_qualifier(gx_object)
735
+ self.object_map[record.level] = self.object_map[record.level-1]
736
+ else:
737
+ raise ValueError(f"Could not handle 'PAGE' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
738
+
739
+ def handle_plac(self, record: Gedcom5xRecord):
740
+ if isinstance(self.object_map[record.level-1], Agent):
741
+ gxobject = Address(value=record.value)
742
+ self.object_map[record.level-1].add_address(gxobject)
743
+
744
+
745
+ self.object_map[record.level] = gxobject
746
+ elif isinstance(self.object_map[record.level-1], Event):
747
+ if self.gedcomx.places.byName(record.value):
748
+ self.object_map[record.level-1].place = PlaceReference(original=record.value, description=self.gedcomx.places.byName(record.value)[0])
749
+ else:
750
+ place_des = PlaceDescription(names=[TextValue(value=record.value)])
751
+ self.gedcomx.add_place_description(place_des)
752
+ self.object_map[record.level-1].place = PlaceReference(original=record.value, description=place_des)
753
+ if len(record.subRecords()) > 0:
754
+ self.object_map[record.level]= place_des
755
+
756
+ elif isinstance(self.object_map[record.level-1], Fact):
757
+ if self.gedcomx.places.byName(record.value):
758
+ self.object_map[record.level-1].place = PlaceReference(original=record.value, description=self.gedcomx.places.byName(record.value)[0])
759
+ else:
760
+ place_des = PlaceDescription(names=[TextValue(value=record.value)])
761
+ self.gedcomx.add_place_description(place_des)
762
+ self.object_map[record.level-1].place = PlaceReference(original=record.value, description=place_des)
763
+ elif isinstance(self.object_map[record.level-1], SourceDescription):
764
+ gxobject = Note(text='Place: ' + record.value if record.value else 'WARNING: NOTE had no value')
765
+ self.object_map[record.level-1].add_note(gxobject)
766
+
767
+ self.object_map[record.level] = gxobject
768
+ else:
769
+ raise TagConversionError(record=record,levelstack=self.object_map)
770
+
771
+ def handle_post(self, record: Gedcom5xRecord):
772
+ if isinstance(self.object_map[record.level-1], Address):
773
+ self.object_map[record.level-1].postalCode = self.clean_str(record.value)
774
+ else:
775
+ raise ValueError(f"I do not know how to handle an 'POST' tag for a {type(self.object_map[record.level-1])}")
776
+
777
+ def handle_publ(self, record: Gedcom5xRecord):
778
+ if isinstance(self.object_map[record.level-1], SourceDescription):
779
+ if record.value and self.gedcomx.agents.byName(record.value):
780
+ gxobject = self.gedcomx.agents.byName(record.value)[0]
781
+ else:
782
+ gxobject = Agent(names=[TextValue(record.value)])
783
+ self.gedcomx.add_agent(gxobject)
784
+ self.object_map[record.level-1].publisher = gxobject
785
+
786
+
787
+ self.object_map[record.level] = gxobject
788
+ else:
789
+ raise TagConversionError(record=record,levelstack=self.object_map)
790
+
791
+ def handle_prob(self, record: Gedcom5xRecord):
792
+ if isinstance(self.object_map[record.level-1], Person):
793
+ gxobject = Fact(type=FactType.Probate)
794
+ self.object_map[record.level-1].add_fact(gxobject)
795
+
796
+
797
+ self.object_map[record.level] = gxobject
798
+ else:
799
+ raise TagConversionError(record=record,levelstack=self.object_map)
800
+
801
+ def handle_uid(self, record: Gedcom5xRecord):
802
+ if isinstance(self.object_map[record.level-1], Agent):
803
+ gxobject = Identifier(value=[URI('UID:' + record.value)] if record.value else [URI('WARNING: NOTE had no value')],type=IdentifierType.Primary) # type: ignore
804
+ self.object_map[record.level-1].add_identifier(gxobject) #NOTE GC7
805
+
806
+ self.object_map[record.level] = gxobject
807
+
808
+ def handle_refn(self, record: Gedcom5xRecord):
809
+ if isinstance(self.object_map[record.level-1], Person) or isinstance(self.object_map[record.level-1], SourceDescription):
810
+ gxobject = Identifier(value=[URI.from_url('Reference Number:' + record.value)] if record.value else [])
811
+ self.object_map[record.level-1].add_identifier(gxobject)
812
+
813
+ self.object_map[record.level] = gxobject
814
+ elif isinstance(self.object_map[record.level-1], Agent):
815
+ gxobject = Identifier(value=[URI('Reference Number:' + record.value)] if record.value else [])
816
+ self.object_map[record.level-1].add_identifier(gxobject) #NOTE GC7
817
+
818
+ self.object_map[record.level] = gxobject
819
+ else:
820
+ raise ValueError(f"Could not handle 'REFN' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
821
+
822
+ def handle_repo(self, record: Gedcom5xRecord):
823
+
824
+ if record.level == 0:
825
+
826
+ gxobject = Agent(id=record.xref)
827
+ self.gedcomx.add_agent(gxobject)
828
+
829
+ self.object_map[record.level] = gxobject
830
+
831
+ elif isinstance(self.object_map[record.level-1], SourceDescription):
832
+ if self.gedcomx.agents.byId(record.xref) is not None:
833
+
834
+ # TODO WHere and what to add this to?
835
+ gxobject = self.gedcomx.agents.byId(record.xref)
836
+ self.object_map[record.level-1].repository = gxobject
837
+ self.object_map[record.level] = gxobject
838
+
839
+ else:
840
+ print("handle_repo",record.describe())
841
+ raise ValueError()
842
+ gxobject = Agent(names=[TextValue(record.value)])
843
+ else:
844
+ 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])}")
845
+
846
+
847
+
848
+ self.object_map[record.level] = gxobject
849
+
850
+ def handle_resi(self, record: Gedcom5xRecord):
851
+ if isinstance(self.object_map[record.level-1], Person):
852
+ gxobject = Fact(type=FactType.Residence)
853
+ if record.value and record.value.strip() != '':
854
+ gxobject.add_note(Note(text=record.value))
855
+ self.object_map[record.level-1].add_fact(gxobject)
856
+
857
+
858
+ self.object_map[record.level] = gxobject
859
+ else:
860
+ raise TagConversionError(record=record,levelstack=self.object_map)
861
+
862
+ def handle_rin(self, record: Gedcom5xRecord):
863
+ if isinstance(self.object_map[record.level-1], SourceDescription):
864
+ self.object_map[record.level-1].id = record.value
865
+ self.object_map[record.level-1].add_note(Note(text=f"Source had RIN: of {record.value}"))
866
+
867
+ else:
868
+ raise ValueError(f"Could not handle 'RIN' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
869
+
870
+ def handle_sex(self, record: Gedcom5xRecord):
871
+
872
+ if isinstance(self.object_map[record.level-1], Person):
873
+ if record.value == 'M':
874
+ gxobject = Gender(type=GenderType.Male)
875
+ elif record.value == 'F':
876
+ gxobject = Gender(type=GenderType.Female)
877
+ else:
878
+ gxobject = Gender(type=GenderType.Unknown)
879
+ self.object_map[record.level-1].gender = gxobject
880
+
881
+
882
+ self.object_map[record.level] = gxobject
883
+ else:
884
+ assert False
885
+
886
+ def handle_sour(self, record: Gedcom5xRecord):
887
+ if record.level == 0 or record.tag == '_WLNK' or (record.level == 0 and record.tag == 'OBJE'):
888
+ source_description = SourceDescription(id=record.xref.replace('@','') if record.xref else None)
889
+ self.gedcomx.add_source_description(source_description)
890
+
891
+ self.object_map[record.level] = source_description
892
+ else:
893
+ # This 'SOUR' is a SourceReference
894
+ if record.xref is None or record.xref.strip() == '':
895
+ log.warning(f"SOUR points to nothing: {record.describe()}")
896
+ return False
897
+ if self.gedcomx.source_descriptions.byId(record.xref):
898
+ gxobject = SourceReference(descriptionId=record.xref, description=self.gedcomx.source_descriptions.byId(record.xref))
899
+ else:
900
+ log.warning(f'Could not find source with id: {record.xref}')
901
+ source_description = SourceDescription(id=record.xref)
902
+ gxobject = SourceReference(descriptionId=record.value, description=source_description)
903
+ if isinstance(self.object_map[record.level-1],SourceReference):
904
+ self.object_map[record.level-1].description.add_source(gxobject)
905
+ elif record.parent is not None and record.parent.tag in ['NOTE']:
906
+ pass
907
+ else:
908
+ self.object_map[record.level-1].add_source(gxobject)
909
+
910
+ self.object_map[record.level] = gxobject
911
+
912
+ def handle_stae(self, record: Gedcom5xRecord):
913
+ if isinstance(self.object_map[record.level-1], Address):
914
+ self.object_map[record.level-1].stateOrProvince = self.clean_str(record.value)
915
+ else:
916
+ raise ValueError(f"I do not know how to handle an 'STAE' tag for a {type(self.object_map[record.level-1])}")
917
+
918
+ def handle_surn(self, record: Gedcom5xRecord):
919
+ if isinstance(self.object_map[record.level-1], Name):
920
+ surname = NamePart(value=record.value, type=NamePartType.Surname)
921
+ self.object_map[record.level-1]._add_name_part(surname)
922
+ else:
923
+ raise TagConversionError(record=record,levelstack=self.object_map)
924
+
925
+ def handle_text(self, record: Gedcom5xRecord):
926
+ if record.parent is not None and record.parent.tag == 'DATA':
927
+ if isinstance(self.object_map[record.level-2], SourceReference):
928
+ gxobject = TextValue(value=record.value)
929
+ self.object_map[record.level-2].description.add_description(gxobject)
930
+
931
+ self.object_map[record.level] = gxobject
932
+ elif isinstance(self.object_map[record.level-1], SourceDescription):
933
+ gxobject = Document(text=record.value)
934
+ self.object_map[record.level-1].analysis = gxobject
935
+ else:
936
+ assert False
937
+
938
+ def handle_titl(self, record: Gedcom5xRecord):
939
+ if isinstance(self.object_map[record.level-1], SourceDescription):
940
+
941
+ gxobject = TextValue(value=self.clean_str(record.value))
942
+ self.object_map[record.level-1].add_title(gxobject)
943
+
944
+
945
+ self.object_map[record.level] = gxobject
946
+
947
+ elif record.parent is not None and record.parent.tag == 'FILE' and isinstance(self.object_map[record.level-2], SourceDescription):
948
+ gxobject = TextValue(value=record.value)
949
+ self.object_map[record.level-2].add_title(gxobject)
950
+
951
+
952
+ self.object_map[record.level] = gxobject
953
+ elif self.object_map[record.level] and isinstance(self.object_map[record.level], Name):
954
+ gxobject = NamePart(value=record.value, qualifiers=[NamePartQualifier.Title])
955
+
956
+ self.object_map[record.level]._add_name_part(gxobject)
957
+ else:
958
+ log.error(f"raise TagConversionError(record=record,levelstack=self.object_map)")
959
+
960
+ def handle_tran(self, record: Gedcom5xRecord):
961
+ pass
962
+
963
+ def handle_type(self, record: Gedcom5xRecord):
964
+ # peek to see if event or fact
965
+ if isinstance(self.object_map[record.level-1], Event):
966
+ if EventType.guess(record.value):
967
+ self.object_map[record.level-1].type = EventType.guess(record.value)
968
+ else:
969
+ log.warning(f"Could not determine type of event with value '{record.value}'")
970
+ assert False
971
+ self.object_map[record.level-1].type = None
972
+ self.object_map[record.level-1].add_note(Note(text=self.clean_str(record.value)))
973
+ elif isinstance(self.object_map[record.level-1], Fact):
974
+ if not self.object_map[record.level-1].type:
975
+ self.object_map[0].type = FactType.guess(record.value)
976
+ elif isinstance(self.object_map[record.level-1], Identifier):
977
+
978
+ self.object_map[record.level-1].values.append(self.clean_str(record.value))
979
+ self.object_map[record.level-1].type = IdentifierType.Other # type: ignore
980
+
981
+ elif record.parent is not None and record.parent.tag == 'FORM':
982
+ if not self.object_map[0].mediaType:
983
+ self.object_map[0].mediaType = record.value
984
+
985
+ else:
986
+ raise ValueError(f"I do not know how to handle 'TYPE' tag for {type(self.object_map[record.level-1])}")
987
+
988
+ def handle__url(self, record: Gedcom5xRecord):
989
+ if isinstance(self.object_map[record.level-2], SourceDescription):
990
+ self.object_map[record.level-2].about = URI.from_url(record.value) if record.value else None
991
+ else:
992
+ raise ValueError(f"Could not handle '_URL' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
993
+
994
+ def handle_www(self, record: Gedcom5xRecord):
995
+ if isinstance(self.object_map[record.level-1], Agent):
996
+ self.object_map[record.level-1].homepage = self.clean_str(record.value)
997
+ elif isinstance(self.object_map[record.level-2], SourceReference):
998
+ self.object_map[record.level-2].description.add_identifier(Identifier(value=[URI.from_url(record.value)] if record.value else []))
999
+ else:
1000
+ raise ValueError(f"Could not handle 'WWW' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
1001
+
1002
+ def Gedcom5x_GedcomX(self, gedcom5x: Gedcom5x):
1003
+ print(f'Parsing GEDCOM Version {gedcom5x.version}')
1004
+ individual_ids = set()
1005
+ source_ids = set()
1006
+ repository_ids = set()
1007
+ family_ids = set()
1008
+
1009
+ if gedcom5x:
1010
+ for individual in gedcom5x.individuals:
1011
+ individual_ids.add(individual.xref)
1012
+ gx_obj = Person(id=individual.xref)
1013
+ self.gedcomx.add_person(gx_obj)
1014
+
1015
+
1016
+ for source in gedcom5x.sources:
1017
+ source_ids.add(source.xref)
1018
+ gx_obj = SourceDescription(id=source.xref)
1019
+ self.gedcomx.add_source_description(gx_obj)
1020
+
1021
+ for source in gedcom5x.repositories:
1022
+ repository_ids.add(source.xref)
1023
+ gx_obj = Agent(id=source.xref)
1024
+ self.gedcomx.add_agent(gx_obj)
1025
+
1026
+ for family in gedcom5x.families:
1027
+ family_ids.add(family.xref)
1028
+ self.handle_fam(family)
1029
+
1030
+ # Now Parse Zero Level Recrods
1031
+ for individual in gedcom5x.individuals:
1032
+ self.parse_gedcom5x_recrod(individual)
1033
+
1034
+ return self.gedcomx