gedcom-x 0.5.6__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.
- {gedcom_x-0.5.6.dist-info → gedcom_x-0.5.7.dist-info}/METADATA +1 -1
- gedcom_x-0.5.7.dist-info/RECORD +49 -0
- gedcomx/Address.py +13 -13
- gedcomx/Agent.py +28 -16
- gedcomx/Attribution.py +34 -7
- gedcomx/Conclusion.py +24 -13
- gedcomx/Converter.py +1034 -0
- gedcomx/Coverage.py +7 -6
- gedcomx/Date.py +11 -4
- gedcomx/Document.py +2 -1
- gedcomx/Event.py +95 -20
- gedcomx/Extensions/__init__.py +1 -0
- gedcomx/Extensions/rs10/__init__.py +1 -0
- gedcomx/Extensions/rs10/rsLink.py +116 -0
- gedcomx/Fact.py +16 -13
- gedcomx/Gedcom5x.py +78 -61
- gedcomx/GedcomX.py +182 -1039
- gedcomx/Gender.py +7 -9
- gedcomx/Identifier.py +9 -12
- gedcomx/LoggingHub.py +21 -0
- gedcomx/Mutations.py +8 -8
- gedcomx/Name.py +207 -87
- gedcomx/Note.py +16 -9
- gedcomx/Person.py +39 -18
- gedcomx/PlaceDescription.py +70 -19
- gedcomx/PlaceReference.py +40 -8
- gedcomx/Qualifier.py +39 -12
- gedcomx/Relationship.py +5 -3
- gedcomx/Resource.py +38 -28
- gedcomx/Serialization.py +773 -358
- gedcomx/SourceDescription.py +133 -74
- gedcomx/SourceReference.py +10 -9
- gedcomx/Subject.py +5 -21
- gedcomx/Translation.py +976 -1
- gedcomx/URI.py +1 -1
- gedcomx/__init__.py +3 -2
- gedcom_x-0.5.6.dist-info/RECORD +0 -45
- {gedcom_x-0.5.6.dist-info → gedcom_x-0.5.7.dist-info}/WHEEL +0 -0
- {gedcom_x-0.5.6.dist-info → gedcom_x-0.5.7.dist-info}/top_level.txt +0 -0
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
|