0005620: Export name types to GEDCOM. Patch extended following testing against various GEDCOM files from the internet.

svn: r19053
This commit is contained in:
Tim G L Lyons 2012-03-13 17:09:08 +00:00
parent 88df9c000f
commit 9c4f7b7e0a
2 changed files with 177 additions and 31 deletions

View File

@ -1257,6 +1257,14 @@ class GedcomWriter(UpdateCallback):
nick = attr_nick
self.__writeln(1, 'NAME', gedcom_name)
if int(name.get_type()) == gen.lib.NameType.BIRTH:
pass
elif int(name.get_type()) == gen.lib.NameType.MARRIED:
self.__writeln(2, 'TYPE', 'married')
elif int(name.get_type()) == gen.lib.NameType.AKA:
self.__writeln(2, 'TYPE', 'aka')
else:
self.__writeln(2, 'TYPE', name.get_type().xml_str())
if firstname:
self.__writeln(2, 'GIVN', firstname)

View File

@ -255,6 +255,8 @@ TOKEN_WWW = 125
TOKEN_URL = 126
TOKEN_ROLE = 127
TOKEN__MAR = 128
TOKEN__MARN = 129
TOKEN__ADPN = 130
TOKENS = {
"HEAD" : TOKEN_HEAD, "MEDI" : TOKEN_MEDI,
@ -268,6 +270,7 @@ TOKENS = {
"ADDRESS2" : TOKEN_ADR2, "AFN" : TOKEN_AFN,
"AGE" : TOKEN_AGE, "AGNC" : TOKEN_AGNC,
"AGENCY" : TOKEN_IGNORE, "_AKA" : TOKEN__AKA,
"_AKAN" : TOKEN__AKA, "AKA" : TOKEN__AKA,
"_ALIA" : TOKEN_ALIA, "ALIA" : TOKEN_ALIA,
"ALIAS" : TOKEN_ALIA, "ANCI" : TOKEN_ANCI,
"ASSO" : TOKEN_ASSO, "ASSOCIATES" : TOKEN_ASSO,
@ -358,7 +361,8 @@ TOKENS = {
"FACT" : TOKEN_FACT, "EMAIL" : TOKEN_EMAIL,
"EMAI" : TOKEN_EMAIL, "WWW" : TOKEN_WWW,
"_URL" : TOKEN_URL, "URL" : TOKEN_URL,
"_MAR" : TOKEN__MAR,
"_MAR" : TOKEN__MAR, "_MARN" : TOKEN__MARN,
"_ADPN" : TOKEN__ADPN
}
ADOPT_NONE = 0
@ -1928,7 +1932,7 @@ class GedcomParser(UpdateCallback):
# +1 REFN <USER_REFERENCE_NUMBER> {0:M}
# +2 TYPE <USER_REFERENCE_TYPE> {0:1}
TOKEN_REFN : self.__person_attr,
# TYPE should be eblow REFN, but will work here anyway
# TYPE should be below REFN, but will work here anyway
TOKEN_TYPE : self.__person_attr,
# +1 RIN <AUTOMATED_RECORD_ID> {0:1}
TOKEN_RIN : self.__person_attr,
@ -1964,10 +1968,18 @@ class GedcomParser(UpdateCallback):
# Extensions
TOKEN_ALIA : self.__name_alia,
TOKEN__MARNM : self.__name_marnm,
TOKEN__MAR : self.__name_marnm, # Generated by gni.com
TOKEN__AKA : self.__name_aka,
TOKEN_TYPE : self.__name_type,
TOKEN__MAR : self.__name_marnm, # Generated by geni.com
TOKEN__MARN : self.__name_marnm, # Gen'd by BROSKEEP 6.1.31 WIN
TOKEN__AKA : self.__name_aka, # PAF and AncestQuest
TOKEN_TYPE : self.__name_type, # This is legal GEDCOM 5.5.1
TOKEN_BIRT : self.__ignore,
TOKEN_DATE : self.__name_date,
# This handles date as a subsidiary of "1 ALIA" which might be used
# by Family Tree Maker and Reunion, and by cheating (handling a
# lower level from the current parse table) handles date as
# subsidiary to "2 _MARN", "2 _AKAN" and "2 _ADPN" which has been
# found in Brother's keeper.
TOKEN__ADPN : self.__name_adpn,
}
#
@ -3143,8 +3155,13 @@ class GedcomParser(UpdateCallback):
@param state: The current state
@type state: CurrentState
"""
# We can get here when a tag that is not valid in the indi_parse_tbl
# parse table is encountered. It is remotely possible that this is
# actally a DATE tag, in which case line.data will be a date object, so
# we need to convert it back to a string here.
event_ref = self.__build_event_pair(state, gen.lib.EventType.CUSTOM,
self.event_parse_tbl, line.data)
self.event_parse_tbl,
str(line.data))
state.person.add_event_ref(event_ref)
def __fam_even(self, line, state):
@ -3184,14 +3201,41 @@ class GedcomParser(UpdateCallback):
def __person_alt_name(self, line, state):
"""
This parses the standard GEDCOM structure:
n @XREF:INDI@ INDI {1:1}
+1 ALIA @<XREF:INDI>@ {0:M}
The ALIA tag is supposed to cross reference another person. We will
store this in the Association record.
ALIA {ALIAS}: = An indicator to link different record descriptions of a
person who may be the same person.
Some systems use the ALIA tag as an alternate NAME tag, which
is not legal in GEDCOM, but oddly enough, is easy to support.
Some systems use the ALIA tag as an alternate NAME tag, which is not
legal in GEDCOM, but oddly enough, is easy to support. This parses the
illegal (ALIA or ALIAS) or non-standard (_ALIA) GEDCOM. "1 ALIA" is used
by Family Tree Maker and Reunion. "1 ALIAS" and "1 _ALIA" do not appear
to be used.
n @XREF:INDI@ INDI {1:1}
+1 <ALIA> <NAME_PERSONAL> {1:1}
+2 NPFX <NAME_PIECE_PREFIX> {0:1}
+2 GIVN <NAME_PIECE_GIVEN> {0:1}
+2 NICK <NAME_PIECE_NICKNAME> {0:1}
+2 SPFX <NAME_PIECE_SURNAME_PREFIX> {0:1}
+2 SURN <NAME_PIECE_SURNAME> {0:1}
+2 NSFX <NAME_PIECE_SUFFIX> {0:1}
+2 <<SOURCE_CITATION>> {0:M}
+3 <<NOTE_STRUCTURE>> {0:M}
+3 <<MULTIMEDIA_LINK>> {0:M}
+2 <<NOTE_STRUCTURE>> {0:M}
where <ALIA> == ALIA | _ALIA | ALIAS
@param line: The current line in GedLine format
@type line: GedLine
@param state: The current state
@type state: CurrentState
"""
if line.data[0] == '@':
handle = self.__find_person_handle(self.pid_map[line.data])
@ -3204,11 +3248,23 @@ class GedcomParser(UpdateCallback):
def __parse_alias_name(self, line, state):
"""
Parse a altername name, usually indicated by a AKA or _AKA
tag. This is not valid GEDCOM, but several programs will add
this just to make life interesting. Odd, since GEDCOM supports
multiple NAME indicators, which is the correct way of handling
multiple names.
Parse a level 1 alias name and subsidiary levels when called from
__person_alt_name (when the <NAME_PERSONAL> does not start with @). Also
parses a level 2 alias name and subsidiary levels when called from
__name_alias.
+1 <ALIA> <NAME_PERSONAL> {1:1}
+2 NPFX <NAME_PIECE_PREFIX> {0:1}
+2 GIVN <NAME_PIECE_GIVEN> {0:1}
+2 NICK <NAME_PIECE_NICKNAME> {0:1}
+2 SPFX <NAME_PIECE_SURNAME_PREFIX> {0:1}
+2 SURN <NAME_PIECE_SURNAME> {0:1}
+2 NSFX <NAME_PIECE_SUFFIX> {0:1}
+2 <<SOURCE_CITATION>> {0:M}
+3 <<NOTE_STRUCTURE>> {0:M}
+3 <<MULTIMEDIA_LINK>> {0:M}
+2 <<NOTE_STRUCTURE>> {0:M}
where <ALIA> == ALIA | _ALIA | ALIAS
@param line: The current line in GedLine format
@type line: GedLine
@ -3595,11 +3651,23 @@ class GedcomParser(UpdateCallback):
@param state: The current state
@type state: CurrentState
"""
if line.data == "_OTHN":
if line.data.upper() in ("_OTHN", "_AKA", "AKA", "AKAN"):
state.name.set_type(gen.lib.NameType.AKA)
elif line.data.upper() in ("_MAR", "_MARN", "_MARNM", "MARRIED"):
state.name.set_type(gen.lib.NameType.MARRIED)
else:
state.name.set_type((gen.lib.NameType.CUSTOM, line.data))
def __name_date(self, line, state):
"""
@param line: The current line in GedLine format
@type line: GedLine
@param state: The current state
@type state: CurrentState
"""
if state.name:
state.name.set_date_object(line.data)
def __name_note(self, line, state):
"""
@param line: The current line in GedLine format
@ -3611,27 +3679,46 @@ class GedcomParser(UpdateCallback):
def __name_alia(self, line, state):
"""
This handles the ALIA (or _ALIA or ALIAS) tag as a subsidiary of the
NAME tag. For example:
This parses the illegal (ALIA or ALIAS) or non-standard (_ALIA) GEDCOM
tag as a subsidiary of the NAME tag.
0 @PERSON1@ INDI
1 NAME John /Doe/
2 GIVN John
2 SURN Doe
2 ALIA Richard /Roe/
2 NPFX Dr.
2 GIVN Richard
2 NICK Rich
2 SPFX Le
n @XREF:INDI@ INDI {1:1}
+1 NAME <NAME_PERSONAL> {1:1}
+2 NPFX <NAME_PIECE_PREFIX> {0:1}
+2 GIVN <NAME_PIECE_GIVEN> {0:1}
+2 NICK <NAME_PIECE_NICKNAME> {0:1}
+2 SPFX <NAME_PIECE_SURNAME_PREFIX> {0:1}
+2 SURN <NAME_PIECE_SURNAME> {0:1}
+2 NSFX <NAME_PIECE_SUFFIX> {0:1}
+2 <ALIA> <NAME_PERSONAL> {1:1}
+3 NPFX <NAME_PIECE_PREFIX> {0:1}
+3 GIVN <NAME_PIECE_GIVEN> {0:1}
+3 NICK <NAME_PIECE_NICKNAME> {0:1}
+3 SPFX <NAME_PIECE_SURNAME_PREFIX> {0:1}
+3 SURN <NAME_PIECE_SURNAME> {0:1}
+3 NSFX <NAME_PIECE_SUFFIX> {0:1}
+3 <<SOURCE_CITATION>> {0:M}
+4 <<NOTE_STRUCTURE>> {0:M}
+4 <<MULTIMEDIA_LINK>> {0:M}
+3 <<NOTE_STRUCTURE>> {0:M}
+2 <<SOURCE_CITATION>> {0:M}
+3 <<NOTE_STRUCTURE>> {0:M}
+3 <<MULTIMEDIA_LINK>> {0:M}
+2 <<NOTE_STRUCTURE>> {0:M}
Note that the subsidiary name structure detail will overwrite the ALIA
name (if the same elements are provided in both), so the names should
match.
There does not appear to be any evidence that this usage exists, but as
it was supported (though probably incorrectly coded as it would only
work if the name started with'@'), in previous versions of Gramps, we
had better support it here.
"2 _ALIA" is used for example, by PRO-GEN v 3.0a and "2 ALIA" is used
by GTEdit and Brother's keeper 5.2 for windows. It had been supported in
previous versions of Gramps but as it was probably incorrectly coded as
it would only work if the name started with '@'.
@param line: The current line in GedLine format
@type line: GedLine
@param state: The current state
@type state: CurrentState
"""
self.__parse_alias_name(line, state)
@ -3689,6 +3776,16 @@ class GedcomParser(UpdateCallback):
def __name_marnm(self, line, state):
"""
This is non-standard GEDCOM. _MARNM is reported to be used in Ancestral
Quest and Personal Ancestral File 5. This will also handle a usage which
has been found in Brother's Keeper (BROSKEEP VERS 6.1.31 WINDOWS) as
follows:
0 @I203@ INDI
1 NAME John Richard/Doe/
2 _MARN Some Other Name
3 DATE 27 JUN 1817
@param line: The current line in GedLine format
@type line: GedLine
@param state: The current state
@ -3737,6 +3834,22 @@ class GedcomParser(UpdateCallback):
def __name_aka(self, line, state):
"""
This parses the non-standard GEDCOM tags _AKA or _AKAN as a subsidiary
to the NAME tag, which is reported to have been found in Ancestral Quest
and Personal Ancestral File 4 and 5. Note: example AQ and PAF files have
separate 2 NICK and 2 _AKA lines for the same person. The NICK will be
stored by Gramps in the nick_name field of the name structure, while the
_AKA, if it is a single word, will be stored in the NICKNAME attribute.
If more than one word it is stored as an AKA alternate name.
This will also handle a usage which has been found in in Brother's
Keeper (BROSKEEP VERS 6.1.31 WINDOWS) as follows:
0 @I203@ INDI
1 NAME John Richard/Doe/
2 _AKAN Some Other Name
3 DATE 27 JUN 1817
@param line: The current line in GedLine format
@type line: GedLine
@param state: The current state
@ -3756,8 +3869,33 @@ class GedcomParser(UpdateCallback):
surname.set_primary()
name.set_surname_list([surname])
name.set_first_name(' '.join(lname[0:name_len-1]))
# name = self.__parse_name_personal(line.data)
name.set_type(gen.lib.NameType.AKA)
state.person.add_alternate_name(name)
def __name_adpn(self, line, state):
"""
@param line: The current line in GedLine format
@type line: GedLine
@param state: The current state
@type state: CurrentState
"""
text = line.data.strip()
data = text.split()
if len(data) == 1:
name = gen.lib.Name(state.person.primary_name)
surn = gen.lib.Surname()
surn.set_surname(data[0].strip())
surn.set_primary()
name.set_surname_list([surn])
name.set_type((gen.lib.NameType.CUSTOM, "Adopted"))
state.person.add_alternate_name(name)
elif len(data) > 1:
name = self.__parse_name_personal(text)
name.set_type((gen.lib.NameType.CUSTOM, "Adopted"))
state.person.add_alternate_name(name)
def __name_sour(self, line, state):
"""
@param line: The current line in GedLine format