Place (location) as a pointer

A question came up recently about how locations/places are handled in the family module. According to the GEDCOM 5.5.1 specification A place is a subordinate fact to a single parent fact and cannot be shared requiring duplicate entry of location data. I propose that we break with the GEDCOM specification in this instance to allow locations (PLAC fact_codes) to share the same architecture (with one modification) as source facts (SOUR fact_code). This will require some changes to the way we import GEDCOMS because we will have to look at each fact_code looking for the PLAC special case and executing the specialized execution code. We will also have to make the same accordances in the export code when we get around to writing it. I think these are reasonable concessions for removing the redundancy and complications of supporting the existing PLAC structure.

In essence, the new structure will be as follows:
1) A PLAC fact will be a root level fact (like SOUR, INDI, REPO, etc) with an assigned unique xref (with an xref prefix of P). The PLAC will have the same structure thereunder as the existing GEDCOM 5.5.1 specification dictates with one exception. The root PLAC fact-value shall be blank (instead of the place name) and the place name shall be stored as a subordinate NAME fact (consistent with other root level fact structures).

2) When associating a PLAC fact with any other fact the PLAC fact-value will be the xref of the desired PLAC (consistent with source/citation fact structures).

3) A PLAC pointer (think source citation) may override the PLAC LATI and LONG and include a NOTE field. This will allow more specific coordinates to be listed for the same location. Example: We have a PLAC describing a cemetery with latitude and longitude coordinates. We have several pointers to this cemetery originating to burial events. We know the coordinates for some of the graves and want to enter these in for the specific burial without overriding the existing cemetery coordinates. Placing the grave site coordinates in the PLAC pointers supersede the cemetery coordinates without destroying them. To edit the coordinates for the cemetery we would have to go to the location node and edit it there. Adding the note in the pointer is consistent with source/citation structure. The ability of citation (pointer) data to supersede source (place) data is a unique feature.

In GEDCOM form this would look like:
PLAC as a root fact -
0 @P1@ PLAC
1 NAME Durham, North Carolina, USA
1 MAP
2 LATI 35.993
2 LONG -78.898
1 SOUR @S1@

PLAC as a subordinate fact -
0 INDI
1 NAME John /Doe/
1 BIRT
2 DATE 01 Jan 1900
2 PLAC @P1@
1 DEAT
2 DATE 31 Dec 2006
2 PLAC @P1@
1 BURI
2 PLAC @P1@
3 MAP
4 LATI 35.995324
4 LONG -78.927278
3 NOTE The gravestone is 2 feet tall and is inscribed with ...

Implementation
While we may use this structure internally, we will not receive GEDCOMS formed this way. If we attempted to export this structure we would be giving users a malformed GEDCOM. To promote GEDCOM harmony we need to adapt the importer and exporter to translate between the GEDCOM specified form and our own. After all, an interchange format1 is of no use if applications do not follow the rules.

Import
When the import script detects a PLAC fact we need to:

  1. Check for an existing matching root PLAC
  2. If no match is found create a new root PLAC, moving the PLAC fact value to a NAME subfact value, and a PLAC node.2
  3. Create a PLAC pointer with xref pointer as the PLAC fact value

We should consider including a PLAC merging tool (wizard?) to help users clean up all the PLAC nodes created by slight variations in spelling. For example: the import will show both Durham, Durham, North Carolina and Durham, Durham, NC and Durham, Durham, North Carolina, USA as separate root PLACs, each with their own node. We should allow users to merge these together.3 We can even prompt the user on the import done page to see if they would like to go ahead and use the tool then. Of course family administrator permissions would be required.4

Export
When the export script detects a pointer we need to:

  1. Get the full PLAC pointer (PP) in a fact data structure5
  2. Follow the xref pointer to the corresponding PLAC and create a full PLAC (P) fact data structure
  3. Replace the PLAC value in the PP data structure with the value of NAME fact in the P data structure
  4. Merge fact values that don't exisit in the PP data structure but do in the P data structure into the PP structure6
  5. Write out the updated PP data structure to the GEDCOM.
  1. This is what GEDCOM is intended to be. It is for that reason we import and export it.
  2. Do we want to assume that additional plac data belongs in the PLAC or in the pointer for first instances? Maybe we want to put it in both?
  3. This could be done by replacing the pointer values (xrefs) matching the unwanted node xref with the xref of the kept node and then deleting the unwanted node.
  4. Or do we want to allow the administrator to change that in the module settings?
  5. use family_get_subfacts($fid)
  6. Where ( (PP->fact !exist) and (P->fact exist) ) => PP->fact = P->fact