requireManagerLogin() ->setPageTitle(WT_I18N::translate('GEDCOM checker').' - '.$GEDCOM) ->pageHeader(); //////////////////////////////////////////////////////////////////////////////// // Scan the data directory for gedcom files //////////////////////////////////////////////////////////////////////////////// $DATA_DIR=get_site_setting('INDEX_DIRECTORY'); $all_geds=array(); $dir=opendir($DATA_DIR); while ($file=readdir($dir)) { if (!is_dir($DATA_DIR.$file) && is_readable($DATA_DIR.$file)) { $h=fopen($DATA_DIR.$file, 'r'); if (preg_match('/0.*HEAD/i', fgets($h,255))) $all_geds[$file]=$DATA_DIR.$file; fclose($h); } } closedir($dir); if (count($all_geds)==0) { $all_geds[]='-'; } else { uasort($all_geds, 'utf8_strcasecmp'); } //////////////////////////////////////////////////////////////////////////////// // User parameters //////////////////////////////////////////////////////////////////////////////// $critical=0; $error=1; $warning=2; $info=3; $levels=array( $critical=>WT_I18N::translate('Critical'), $error =>WT_I18N::translate('Error'), $warning =>WT_I18N::translate('Warning'), $info =>WT_I18N::translate('Info'), ); // Default values if (isset($GEDCOM) && array_key_exists($GEDCOM, $all_geds)) $default_ged=$GEDCOM; // Current gedcom else { $tmp=array_keys($all_geds); $default_ged=$tmp[0]; // First gedcom in directory } $ged =safe_POST('ged', preg_quote_array(array_keys($all_geds)), $default_ged); $err_level =safe_POST('err_level', '[0-3]', $critical); // Higher numbers are more picky. $openinnew =safe_POST('openinnew', '[01]', '0'); // Open links in same/new tab/window $context_lines=safe_POST('context_lines','[0-5]', '2'); // Lines of context to display $showall =safe_POST('showall', '[01]', '0'); // Show details of records with no problems echo '
'; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo '
', WT_I18N::translate('GEDCOM File:'), '
', WT_I18N::translate('Level'), '
', WT_I18N::translate('Open links in'), '
', WT_I18N::translate('Lines of GEDCOM context'), '
', WT_I18N::translate('Show'), '

'; // Do not run until user clicks "show", as default page may take a while to load. // Instead, show some useful help info. if (!isset($_POST['action'])) { echo '

', WT_I18N::translate('This module checks the format of a GEDCOM file against the 5.5.1 GEDCOM Specification. It also checks for a number of common errors in your data. Note that there are lots of versions, extensions and variations on the specification so you should not be concerned with any issues other than those flagged as "Critical". The explanation for all the line-by-line errors can be found in the specification, so please check there before asking for help.'), '


'; exit(); } // If we're checking a gedcom that is imported into the database, check that the file is synchronised if ($ged==WT_GEDCOM) { $ged_link='href="#" onclick="window.open(\''."export_gedcom.php?export=".rawurlencode($ged).'\', \'_blank\',\'left=50,top=50,width=500,height=500,resizable=1,scrollbars=1\');"'; echo '
', WT_I18N::translate('Edits made to the database are not synchronized to the file %s. The file contents may be out-of-date. You can synchronize it with the database now by performing an export.', $ged, $ged_link), '

'; } // Special cases. Other facts link to themselves; SUBN, SUBN, OBJE, NOTE, REPO, SOUR $XREF_LINK=array( 'FAMC'=>'FAM', 'FAMS'=>'FAM', 'HUSB'=>'INDI', 'WIFE'=>'INDI', 'CHIL'=>'INDI', 'ASSO'=>'INDI', 'ALIA'=>'INDI', 'ANCI'=>'SUBM', 'DESI'=>'SUBM', '_WT_OBJE_SORT'=>'OBJE', 'AUTH'=>'INDI' // This is not valid gedcom, but it is not an error if used. ); // Match end of line in DOS/UNIX/MAC format $EOL='[\n\r]+'; //////////////////////////////////////////////////////////////////////////////// // Create error messages //////////////////////////////////////////////////////////////////////////////// function missing ($text) { return WT_I18N::translate('missing') .' ‎'.$text.' ‎'; } function multiple($text) { return WT_I18N::translate('multiple').' ‎'.$text.' ‎'; } function invalid ($text) { return WT_I18N::translate('invalid') .' ‎'.$text.' ‎'; } function too_many($text) { return WT_I18N::translate('too many').' ‎'.$text.' ‎'; } function too_few ($text) { return WT_I18N::translate('too few') .' ‎'.$text.' ‎'; } function no_link ($text) { return '‎'.$text.'‎ '.WT_I18N::translate('does not link back');} //////////////////////////////////////////////////////////////////////////////// // Create a link to a WT object //////////////////////////////////////////////////////////////////////////////// $WT_LINK=array( 'INDI'=>'individual.php?pid=', 'FAM'=>'family.php?famid=', 'SOUR'=>'source.php?sid=', 'REPO'=>'repo.php?rid=', 'OBJE'=>'mediaviewer.php?mid=', 'NOTE'=>'note.php?nid=' ); $target=($openinnew==1 ? ' target="_new"' : ''); function wt_href($tag, $xref, $name='') { global $WT_LINK, $target, $ged; $text=($name=='' ? "$tag $xref" : "$name ($xref)"); if (isset($WT_LINK[$tag]) && get_id_from_gedcom($ged)) { return '‎'.$text.'‎'; } else { return "‎$tag $xref‎"; } } //////////////////////////////////////////////////////////////////////////////// // Valid tags and their context - see Gedcom 5.5.1, pages 23-65 //////////////////////////////////////////////////////////////////////////////// $DAY ='(0?[1-9]|[12][0-9]|30|31)'; $MONTH ='(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)'; $YEAR ='([0-9]{3,4})'; $YEAR_GREG ='([0-9]{3,4}(\/[0-9][0-9])?)'; $MONTH_FREN ='(VEND|BRUM|FRIM|NIVO|PLUV|VENT|GERM|FLOR|PRAI|MESS|THER|FRUC|COMP)'; $MONTH_HEBR ='(TSH|CSH|KSL|TVT|SHV|ADR|ADS|NSN|IYR|SVN|TMZ|AAV|ELL)'; $DATE_FREN ="(@#DFRENCH R@ (($DAY )?$MONTH_FREN )?$YEAR)"; $DATE_HEBR ="(@#DHEBREW@ (($DAY )?$MONTH_HEBR )?$YEAR)"; $DATE_GREG ="((@#DGREGORIAN@ )?((($DAY )?$MONTH )?$YEAR_GREG|$YEAR(B\.C\.)))"; $DATE_JULN ="(@#DJULIAN@ ((($DAY ?)$MONTH ?)$YEAR|$YEAR(B\.C\.)))"; $DATE ="($DATE_GREG|$DATE_JULN|$DATE_HEBR|$DATE_FREN)"; $DATE_EXACT ="($DAY $MONTH $YEAR_GREG)"; $ATTRIBUTE_TYPE ='(CAST|EDUC|NATI|OCCU|PROP|RELI|RESI|TITL|FACT)'; $EVENT_TYPE_FAMILY ='(ANUL|CENS|DIV|DIVF|ENGA|MARR|MARB|MARC|MARL|MARS|EVEN)'; $EVENT_TYPE_INDIVIDUAL ='(ADOP|BIRT|BAPM|BARM|BASM|BLES|BURI|CENS|CHR|CHRA|CONF|CREM|DEAT|EMIG|FCOM|GRAD|IMMI|NATU|ORDN|RETI|PROB|WILL|EVEN)'; $LANGUAGE_ID ='(Afrikaans|Albanian|Anglo-Saxon|Catalan|Catalan_Spn|Czech|Danish|Dutch|English|Esperanto|Estonain|Faroese|Finnish|French|German|Hawaiian|Hungarian|Icelandic|Indonesian|Italian|Latvian|Lithuanian|Navaho|Norwegian|Polish|Portuguese|Romanian|Serbo_Croa|Slovak|Slovene|Spanish|Swedish|Turkish|Wendic|Amharic|Arabic|Armenian|Assamese|Belorussian|Bengali|Braj|Bulgarian|Burmese|Cantonese|Church-Slavic|Dogri|Georgian|Greek|Gujarati|Hebrew|Hindi|Japanese|Kannada|Khmer|Konkani|Korean|Lahnda|Lao|Macedonian|Maithili|Malayalam|Mandrin|Manipuri|Marathi|Mewari|Nepali|Oriya|Pahari|Pali|Panjabi|Persian|Prakrit|Pusto|Rajasthani|Russian|Sanskrit|Serb|Tagalog|Tamil|Tehugu|Thai|Tibetan|Ukranian|Urdu|Vietnamese|Yiddish)'; //$NAME_TEXT ='\p{L}{1,120}'; //$NAME_PIECE ='\p{L}{1,90}'; // There is no widespread PCRE support for \p $NAME_TEXT ='.{1,120}'; $NAME_PIECE ='.{1,90}'; $RECORD_IDENTIFIER ='[^:]{1,18}'; $REGISTERED_RESOURCE_IDENTIFIER ='[^:]{1,25}'; $TEXT ='.{1,248}'; $PLACE_TEXT =$TEXT; $TAG['DATE_APPROXIMATED'] ="(ABT|CAL|EST) $DATE"; $TAG['DATE_VALUE'] ="($DATE_FREN|$DATE_HEBR|$DATE_JULN|$DATE_GREG)"; $TAG['ADDRESS_CITY'] ='.{1,60}'; $TAG['ADDRESS_COUNTRY'] ='.{1,60}'; $TAG['ADDRESS_EMAIL'] ='.{5,120}'; $TAG['ADDRESS_FAX'] ='.{1,60}'; $TAG['ADDRESS_LINE'] ='.{1,60}'; $TAG['ADDRESS_LINE1'] ='.{1,60}'; $TAG['ADDRESS_LINE2'] ='.{1,60}'; $TAG['ADDRESS_LINE3'] ='.{1,60}'; $TAG['ADDRESS_POSTAL_CODE'] ='.{1,10}'; $TAG['ADDRESS_STATE'] ='.{1,60}'; $TAG['ADDRESS_WEB_PAGE'] ='.{5,120}'; $TAG['ADOPTED_BY_WHICH_PARENT'] ='(HUSB|WIFE|BOTH)'; $TAG['AGE_AT_EVENT'] ='([<>]?)(CHILD|INFANT|STILLBORN|([0-9]+y?)?\s*([0-9]+m)?\s*([0-9]+d)?)'; $TAG['ANCESTRAL_FILE_NUMBER'] ='.{1,12}'; $TAG['APPROVED_SYSTEM_ID'] ='.{1,20}'; $TAG['ATTRIBUTE_DESCRIPTOR'] ='.{1,90}'; $TAG['AUTOMATED_RECORD_ID'] ='.{1,12}'; $TAG['CASTE_NAME'] ='.{1,90}'; $TAG['CAUSE_OF_EVENT'] ='.{1,90}'; $TAG['CERTAINTY_ASSESSMENT'] ='[0-3]'; $TAG['CHANGE_DATE'] =$DATE_EXACT; $TAG['CHARACTER_SET'] ='(ANSEL|UTF-8|UNICODE|ASCII)'; $TAG['CHILD_LINKAGE_STATUS'] ='(challenged|disproven|proven)'; $TAG['COPYRIGHT_GEDCOM_FILE'] ='.{1,90}'; $TAG['COPYRIGHT_SOURCE_DATA'] ='.{1,90}'; $TAG['COUNT_OF_CHILDREN'] ='[0-9]{1,3}'; $TAG['COUNT_OF_MARRIAGES'] ='[0-9]{1,3}'; $TAG['DATE_LDS_ORD'] =$TAG['DATE_VALUE']; $TAG['DATE_PERIOD'] ="FROM $DATE|TO $DATE|FROM $DATE TO $DATE"; $TAG['DATE_PHRASE'] ='.{1,35}'; $TAG['DATE_RANGE'] ="((BEF|AFT) $DATE|BET $DATE AND $DATE)"; $TAG['DATE_VALUE'] ="($DATE|{$TAG['DATE_PERIOD']}|{$TAG['DATE_RANGE']}|{$TAG['DATE_APPROXIMATED']}|INT $DATE \({$TAG['DATE_PHRASE']}\)|\({$TAG['DATE_PHRASE']}\))"; $TAG['DESCRIPTIVE_TITLE'] ='.{1,248}'; $TAG['EVENT_ATTRIBUTE_TYPE'] ="($EVENT_TYPE_INDIVIDUAL|$EVENT_TYPE_FAMILY|$ATTRIBUTE_TYPE)"; $TAG['EVENT_DESCRIPTOR'] ='.{1,90}'; $TAG['EVENT_OR_FACT_CLASSIFICATION'] ='.{1,90}'; $TAG['ENTRY_RECORDING_DATE'] =$TAG['DATE_VALUE']; $TAG['EVENT_TYPE_CITED_FROM'] =$TAG['EVENT_ATTRIBUTE_TYPE']; $TAG['EVENTS_RECORDED'] ="({$TAG['EVENT_ATTRIBUTE_TYPE']}(, {$TAG['EVENT_ATTRIBUTE_TYPE']})*)"; $TAG['FILE_NAME'] ='.{1,90}'; $TAG['GEDCOM_FORM'] ='(LINEAGE-LINKED)'; $TAG['GEDCOM_CONTENT_DESCRIPTION'] ='.{1,248}'; $TAG['GENERATIONS_OF_ANCESTORS'] ='([1-9][0-9]{0,3})?'; $TAG['GENERATIONS_OF_DESCENDANTS'] ='([1-9][0-9]{0,3})?'; $TAG['LANGUAGE_OF_TEXT'] =$LANGUAGE_ID; $TAG['LANGUAGE_PREFERENCE'] =$LANGUAGE_ID; $TAG['LDS_BAPTISM_DATE_STATUS'] ='(CHILD|COMPLETED|EXCLUDED|PRE-1970|STILLBORN|SUBMITTED|UNCLEARED)'; $TAG['LDS_CHILD_SEALING_DATE_STATUS'] ='(BIC|COMPLETED|EXCLUDED|DNS|PRE-1970|STILLBORN|SUBMITTED|UNCLEARED)'; $TAG['LDS_ENDOWMENT_DATE_STATUS'] ='(CHILD|COMPLETED|EXCLUDED|PRE-1970|STILLBORN|SUBMITTED|UNCLEARED)'; $TAG['LDS_SPOUSE_SEALING_DATE_STATUS']='(CANCELED|COMPLETED|EXCLUDED|DNS\/CAN|PRE-1970|SUBMITTED|UNCLEARED)'; $TAG['MULTIMEDIA_FILE_REFN'] ='.{1,30}'; $TAG['MULTIMEDIA_FORMAT'] ='(bmp|gif|jpeg|ole|pcx|tif|wav)'; $TAG['NAME_OF_BUSINESS'] ='.{1,90}'; $TAG['NAME_OF_FAMILY_FILE'] ='.{1,120}'; $TAG['NAME_OF_PRODUCT'] ='.{1,90}'; $TAG['NAME_OF_REPOSITORY'] ='.{1,90}'; $TAG['NAME_OF_SOURCE_DATA'] ='.{1,90}'; $TAG['NAME_PERSONAL'] ="(($NAME_TEXT)|($NAME_TEXT )*\/$NAME_TEXT\/( $NAME_TEXT)*)"; $TAG['NAME_PHONETIC_VARIATION'] ='.{1,120}'; $TAG['NAME_PIECE_GIVEN'] ="($NAME_PIECE(, $NAME_PIECE)*)"; $TAG['NAME_PIECE_NICKNAME'] ="($NAME_PIECE(, $NAME_PIECE)*)"; $TAG['NAME_PIECE_PREFIX'] ="($NAME_PIECE(, $NAME_PIECE)*)"; $TAG['NAME_PIECE_SUFFIX'] ="($NAME_PIECE(, $NAME_PIECE)*)"; $TAG['NAME_PIECE_SURNAME'] ="($NAME_PIECE(, $NAME_PIECE)*)"; $TAG['NAME_PIECE_SURNAME_PREFIX'] ="($NAME_PIECE(, $NAME_PIECE)*)"; $TAG['NAME_ROMANIZED_VARIATION'] ='.{1,120}'; $TAG['NAME_TYPE'] ='(aka|birth|immigrant|maiden|married|.{5,30})'; $TAG['NATIONAL_ID_NUMBER'] ='.{1,30}'; $TAG['NATIONAL_OR_TRIBAL_ORIGIN'] ='.{1,120}'; $TAG['NOBILITY_TYPE_TITLE'] ='.{1,120}'; $TAG['NULL'] ='^$'; $TAG['OCCUPATION'] ='.{1,90}'; $TAG['ORDINANCE_PROCESS_FLAG'] ='(no|yes)'; $TAG['PEDIGREE_LINKAGE_TYPE'] ='(adopted|birth|foster|sealing)'; $TAG['PERMANENT_RECORD_FILE_NUMBER'] ="($REGISTERED_RESOURCE_IDENTIFIER:$RECORD_IDENTIFIER)"; $TAG['PHONE_NUMBER'] ='.{1,25}'; $TAG['PHONETIC_TYPE'] ='(kana|hangul|.{5,30})'; $TAG['PHYSICAL_DESCRIPTION'] ='.{1,248}'; $TAG['PLACE_HIERARCHY'] ='.{1,120}'; $TAG['PLACE_LATITUDE'] ='([NS][0-9]+(\.[0-9]*)?)'; $TAG['PLACE_LONGITUDE'] ='([EW][0-9]+(\.[0-9]*)?)'; $TAG['PLACE_NAME'] ="($PLACE_TEXT(, $PLACE_TEXT)*)"; $TAG['PLACE_LIVING_ORDINANCE'] =$TAG['PLACE_NAME']; $TAG['PLACE_PHONETIC_VARIATION'] ='.{1,120}'; $TAG['PLACE_ROMANIZED_VARIATION'] ='.{1,120}'; $TAG['POSSESSIONS'] ='.{1,248}'; $TAG['PUBLICATION_DATE'] =$DATE_EXACT; $TAG['RECEIVING_SYSTEM_NAME'] ='(ANSTFILE|TempleReady|.{1,20})'; $TAG['RELATION_IS_DESCRIPTOR'] ='.{1,25}'; $TAG['RELIGIOUS_AFFILIATION'] ='.{1,90}'; $TAG['RESPONSIBLE_AGENCY'] ='.{1,120}'; $TAG['RESTRICTION_NOTICE'] ='(confidential|locked|privacy)'; $TAG['ROLE_DESCRIPTOR'] ='.{1,25}'; $TAG['ROLE_IN_EVENT'] ="(CHIL|HUSB|WIFE|MOTH|FATH|SPOU|\({$TAG['ROLE_DESCRIPTOR']}\))"; $TAG['ROMANIZED_TYPE'] ='(pinyin|ramanji|wadegiles)'; $TAG['SCHOLASTIC_ACHIEVEMENT'] ='.{1,248}'; $TAG['SEX_VALUE'] ='[MFU]'; $TAG['SOCIAL_SECURITY_NUMBER'] ='\d\d\d-\d\d-\d\d\d\d'; $TAG['SOURCE_CALL_NUMBER'] ='.{1,120}'; $TAG['SOURCE_DESCRIPTIVE_TITLE'] ='.{1,248}'; $TAG['SOURCE_FILED_BY_ENTRY'] ='.{1,60}'; $TAG['SOURCE_JURISDICTION_PLACE'] =$TAG['PLACE_NAME']; $TAG['SOURCE_MEDIA_TYPE'] ='audio|book|card|electronic|fiche|film|magazine|manuscript|map|newspaper|photo|tombstone|video'; $TAG['SOURCE_ORIGINATOR'] ='.{1,248}'; $TAG['SOURCE_PUBLICATION_FACTS'] ='.{1,248}'; $TAG['SUBMITTER_NAME'] ='.{1,60}'; $TAG['SUBMITTER_REGISTERED_RFN'] ='.{1,30}'; $TAG['SUBMITTER_TEXT'] ='.{1,248}'; $TAG['TEMPLE_CODE'] ='.{4,5}'; $TAG['TEXT'] ='.{1,248}'; $TAG['TEXT_FROM_SOURCE'] =$TAG['TEXT']; $TAG['TIME_VALUE'] ='([01][0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9](\.[0-9]+)?)?'; $TAG['TRANSMISSION_DATE'] =$DATE_EXACT; $TAG['USER_REFERENCE_NUMBER'] ='.{1,20}'; $TAG['USER_REFERENCE_TYPE'] ='.{1,40}'; $TAG['VERSION_NUMBER'] ='.{1,15}'; $TAG['WHERE_WITHIN_SOURCE'] ='[^:,]+: ?[^:,]+(, ?[^:,]+: ?[^:,]+)*'; $TAG['XREF'] ='@[A-Z0-9!:]{1,22}@'; //////////////////////////////////////////////////////////////////////////////// // Build an array with valid tags and their context //////////////////////////////////////////////////////////////////////////////// $CONTEXT=array(); $CONTEXT_MIN=array(); $CONTEXT_MAX=array(); $CONTEXT_SUB=array(); function add_element($tag, $min, $max, $regex) { global $CONTEXT, $CONTEXT_MIN, $CONTEXT_MAX, $CONTEXT_SUB; $CONTEXT[$tag]=$regex; $CONTEXT_MIN[$tag]=$min; $CONTEXT_MAX[$tag]=$max; $CONTEXT_SUB[$tag]=array(); if (preg_match('/^(.+):([^:]+)$/', $tag, $match)) $CONTEXT_SUB[$match[1]][$match[2]]=$tag; } function add_structure($prefix, $min, $max, $structure) { global $TAG, $CONTEXT; switch ($structure) { case '<>': add_element ($prefix.'ADDR', $min, $max, $TAG['ADDRESS_LINE']); add_element ($prefix.'ADDR:CONT', 0, 3, $TAG['ADDRESS_LINE']); add_element ($prefix.'ADDR:ADR1', 0, 1, $TAG['ADDRESS_LINE1']); add_element ($prefix.'ADDR:ADR2', 0, 1, $TAG['ADDRESS_LINE2']); add_element ($prefix.'ADDR:ADR3', 0, 1, $TAG['ADDRESS_LINE3']); add_element ($prefix.'ADDR:CITY', 0, 1, $TAG['ADDRESS_CITY']); add_element ($prefix.'ADDR:STAE', 0, 1, $TAG['ADDRESS_STATE']); add_element ($prefix.'ADDR:POST', 0, 1, $TAG['ADDRESS_POSTAL_CODE']); add_element ($prefix.'ADDR:CTRY', 0, 1, $TAG['ADDRESS_COUNTRY']); add_element ($prefix.'PHON', 0, 3, $TAG['PHONE_NUMBER']); add_element ($prefix.'EMAIL', 0, 3, $TAG['ADDRESS_EMAIL']); add_element ($prefix.'FAX', 0, 3, $TAG['ADDRESS_FAX']); add_element ($prefix.'WWW', 0, 3, $TAG['ADDRESS_WEB_PAGE']); break; case '<>': add_element ($prefix.'ASSO', $min, $max, $TAG['XREF']); add_element ($prefix.'ASSO:RELA', 1, 1, $TAG['RELATION_IS_DESCRIPTOR']); add_structure($prefix.'ASSO:', 0, 9999, '<>'); add_structure($prefix.'ASSO:', 0, 9999, '<>'); break; case '<>': add_element ($prefix.'CHAN', $min, $max, $TAG['NULL']); add_element ($prefix.'CHAN:DATE', 1, 1, $TAG['CHANGE_DATE']); add_element ($prefix.'CHAN:DATE:TIME', 0, 1, $TAG['TIME_VALUE']); add_structure($prefix.'CHAN:', 0, 9999, '<>'); break; case '<>': add_element ($prefix.'FAMC', $min, $max, $TAG['XREF']); add_element ($prefix.'FAMC:PEDI', 0, 1, $TAG['PEDIGREE_LINKAGE_TYPE']); add_element ($prefix.'FAMC:STAT', 0, 1, $TAG['CHILD_LINKAGE_STATUS']); add_structure($prefix.'FAMC:', 0, 9999, '<>'); break; case '<>': add_element ($prefix.'TYPE', $min, $max, $TAG['EVENT_OR_FACT_CLASSIFICATION']); add_element ($prefix.'DATE', 0, 1, $TAG['DATE_VALUE']); add_structure($prefix, 0, 1, '<>'); add_structure($prefix, 0, 1, '<>'); add_element ($prefix.'AGNC', 0, 1, $TAG['RESPONSIBLE_AGENCY']); add_element ($prefix.'RELI', 0, 1, $TAG['RELIGIOUS_AFFILIATION']); add_element ($prefix.'CAUS', 0, 1, $TAG['CAUSE_OF_EVENT']); add_element ($prefix.'RESN', 0, 1, $TAG['RESTRICTION_NOTICE']); add_structure($prefix, 0, 9999, '<>'); add_structure($prefix, 0, 9999, '<>'); add_structure($prefix, 0, 9999, '<>'); break; case '<>': add_element ($prefix.'HUSB', $min, $max, $TAG['NULL']); add_element ($prefix.'HUSB:AGE', 1, 1, $TAG['AGE_AT_EVENT']); add_element ($prefix.'WIFE', 0, 1, $TAG['NULL']); add_element ($prefix.'WIFE:AGE', 1, 1, $TAG['AGE_AT_EVENT']); add_structure($prefix, 0, 1, '<>'); break; case '<>': add_element ($prefix.'FAM', $min, $max, $TAG['NULL']); add_element ($prefix.'FAM:RESN', 0, 1, $TAG['RESTRICTION_NOTICE']); add_structure($prefix.'FAM:', 0, 9999, '<>'); add_element ($prefix.'FAM:HUSB', 0, 1, $TAG['XREF']); add_element ($prefix.'FAM:WIFE', 0, 1, $TAG['XREF']); add_element ($prefix.'FAM:CHIL', 0, 9999, $TAG['XREF']); add_element ($prefix.'FAM:NCHI', 0, 1, $TAG['COUNT_OF_CHILDREN']); add_element ($prefix.'FAM:SUBM', 0, 9999, $TAG['XREF']); add_structure($prefix.'FAM:', 0, 9999, '<>'); add_element ($prefix.'FAM:REFN', 0, 9999, $TAG['USER_REFERENCE_NUMBER']); add_element ($prefix.'FAM:REFN:TYPE', 0, 1, $TAG['USER_REFERENCE_TYPE']); add_element ($prefix.'FAM:RIN', 0, 1, $TAG['AUTOMATED_RECORD_ID']); add_structure($prefix.'FAM:', 0, 1, '<>'); add_structure($prefix.'FAM:', 0, 9999, '<>'); add_structure($prefix.'FAM:', 0, 9999, '<>'); add_structure($prefix.'FAM:', 0, 9999, '<>'); break; case '<>': foreach (array('ANUL','CENS','DIV','DIVF','ENGA','MARB','MARC','MARL','MARS','RESI') as $event) { add_element ($prefix.$event, $min, $max, $TAG['NULL']); add_structure($prefix.$event.':', 0, 1, '<>'); } add_element ($prefix.'MARR', $min, $max, 'Y?'); add_structure($prefix.'MARR:', 0, 1, '<>'); add_element ($prefix.'EVEN', $min, $max, "(".$TAG['EVENT_DESCRIPTOR'].")?"); add_structure($prefix.'EVEN:', 0, 1, '<>'); break; case '<
>': add_element ($prefix.'HEAD', $min, $max, $TAG['NULL']); add_element ($prefix.'HEAD:SOUR', 1, 1, $TAG['APPROVED_SYSTEM_ID']); add_element ($prefix.'HEAD:SOUR:VERS', 0, 1, $TAG['VERSION_NUMBER']); add_element ($prefix.'HEAD:SOUR:NAME', 0, 1, $TAG['NAME_OF_PRODUCT']); add_element ($prefix.'HEAD:SOUR:CORP', 0, 1, $TAG['NAME_OF_BUSINESS']); add_structure($prefix.'HEAD:SOUR:CORP:', 0, 1, '<>'); add_element ($prefix.'HEAD:SOUR:DATA', 0, 1, $TAG['NAME_OF_SOURCE_DATA']); add_element ($prefix.'HEAD:SOUR:DATA:DATE', 0, 1, $TAG['PUBLICATION_DATE']); add_element ($prefix.'HEAD:SOUR:DATA:COPR', 0, 1, $TAG['COPYRIGHT_SOURCE_DATA']); add_element ($prefix.'HEAD:SOUR:DATA:COPR:CONC', 0, 9999, $TAG['COPYRIGHT_SOURCE_DATA']); add_element ($prefix.'HEAD:SOUR:DATA:COPR:CONT', 0, 9999, $TAG['COPYRIGHT_SOURCE_DATA']); add_element ($prefix.'HEAD:DEST', 0, 1, $TAG['RECEIVING_SYSTEM_NAME']); add_element ($prefix.'HEAD:DATE', 0, 1, $TAG['TRANSMISSION_DATE']); add_element ($prefix.'HEAD:DATE:TIME', 0, 1, $TAG['TIME_VALUE']); add_element ($prefix.'HEAD:SUBM', 1, 1, $TAG['XREF']); add_element ($prefix.'HEAD:SUBN', 0, 1, $TAG['XREF']); add_element ($prefix.'HEAD:FILE', 0, 1, $TAG['FILE_NAME']); add_element ($prefix.'HEAD:COPR', 0, 1, $TAG['COPYRIGHT_GEDCOM_FILE']); add_element ($prefix.'HEAD:GEDC', 1, 1, $TAG['NULL']); add_element ($prefix.'HEAD:GEDC:VERS', 1, 1, $TAG['VERSION_NUMBER']); add_element ($prefix.'HEAD:GEDC:FORM', 1, 1, $TAG['GEDCOM_FORM']); add_element ($prefix.'HEAD:CHAR', 1, 1, $TAG['CHARACTER_SET']); add_element ($prefix.'HEAD:CHAR:VERS', 0, 1, $TAG['VERSION_NUMBER']); add_element ($prefix.'HEAD:LANG', 0, 1, $TAG['LANGUAGE_OF_TEXT']); add_element ($prefix.'HEAD:PLAC', 0, 1, $TAG['NULL']); add_element ($prefix.'HEAD:PLAC:FORM', 1, 1, $TAG['PLACE_HIERARCHY']); add_element ($prefix.'HEAD:NOTE', 0, 1, $TAG['GEDCOM_CONTENT_DESCRIPTION']); add_element ($prefix.'HEAD:NOTE:CONT', 0, 9999, $TAG['GEDCOM_CONTENT_DESCRIPTION']); add_element ($prefix.'HEAD:NOTE:CONC', 0, 9999, $TAG['GEDCOM_CONTENT_DESCRIPTION']); break; case '<>': add_element ($prefix.'CAST', $min, $max, $TAG['CASTE_NAME']); add_structure($prefix.'CAST:', 0, 1, '<>'); add_element ($prefix.'DSCR', $min, $max, $TAG['PHYSICAL_DESCRIPTION']); add_element ($prefix.'DSCR:CONT', 0, 9999, $TAG['PHYSICAL_DESCRIPTION']); add_element ($prefix.'DSCR:CONC', 0, 9999, $TAG['PHYSICAL_DESCRIPTION']); add_structure($prefix.'DSCR:', 0, 1, '<>'); add_element ($prefix.'EDUC', $min, $max, $TAG['SCHOLASTIC_ACHIEVEMENT']); add_structure($prefix.'EDUC:', 0, 1, '<>'); add_element ($prefix.'IDNO', $min, $max, $TAG['NATIONAL_ID_NUMBER']); add_structure($prefix.'IDNO:', 0, 1, '<>'); add_element ($prefix.'NATI', $min, $max, $TAG['NATIONAL_OR_TRIBAL_ORIGIN']); add_structure($prefix.'NATI:', 0, 1, '<>'); add_element ($prefix.'NCHI', $min, $max, $TAG['COUNT_OF_CHILDREN']); add_structure($prefix.'NCHI:', 0, 1, '<>'); add_element ($prefix.'NMR', $min, $max, $TAG['COUNT_OF_MARRIAGES']); add_structure($prefix.'NMR:', 0, 1, '<>'); add_element ($prefix.'OCCU', $min, $max, $TAG['OCCUPATION']); add_structure($prefix.'OCCU:', 0, 1, '<>'); add_element ($prefix.'PROP', $min, $max, $TAG['POSSESSIONS']); add_structure($prefix.'PROP:', 0, 1, '<>'); add_element ($prefix.'RELI', $min, $max, $TAG['RELIGIOUS_AFFILIATION']); add_structure($prefix.'RELI:', 0, 1, '<>'); add_element ($prefix.'RESI', $min, $max, $TAG['NULL']); add_structure($prefix.'RESI:', 0, 1, '<>'); add_element ($prefix.'SSN', $min, $max, $TAG['SOCIAL_SECURITY_NUMBER']); add_structure($prefix.'SSN:', 0, 1, '<>'); add_element ($prefix.'TITL', $min, $max, $TAG['NOBILITY_TYPE_TITLE']); add_structure($prefix.'TITL:', 0, 1, '<>'); add_element ($prefix.'FACT', $min, $max, $TAG['ATTRIBUTE_DESCRIPTOR']); add_structure($prefix.'FACT:', 0, 1, '<>'); break; case '<>': add_structure($prefix, $min, $max, '<>'); add_element ($prefix.'AGE', 0, 1, $TAG['AGE_AT_EVENT']); break; case '<>': foreach (array('BIRT','CHR') as $event) { add_element ($prefix.$event, $min, $max, 'Y?'); add_structure($prefix.$event.':', 0, 1, '<>'); add_element ($prefix.$event.':FAMC', 0, 1, $TAG['XREF']); } foreach (array('DEAT') as $event) { add_element ($prefix.$event, $min, $max, 'Y?'); add_structure($prefix.$event.':', 0, 1, '<>'); } foreach (array('BURI','CREM','BAPM','BARM','BASM','BLES','CHRA','CONF','FCOM','ORDN','NATU','EMIG','IMMI','CENS','PROB','WILL','GRAD','RETI','EVEN') as $event) { add_element ($prefix.$event, $min, $max, $TAG['NULL']); add_structure($prefix.$event.':', 0, 1, '<>'); } add_element ($prefix.'ADOP', $min, $max, $TAG['NULL']); add_structure($prefix.'ADOP:', 0, 1, '<>'); add_element ($prefix.'ADOP:FAMC', 0, 1, $TAG['XREF']); add_element ($prefix.'ADOP:FAMC:ADOP', 0, 1, $TAG['ADOPTED_BY_WHICH_PARENT']); break; case '<>': add_element ('INDI', $min, $max, $TAG['NULL']); add_element ('INDI:RESN', 0, 1, $TAG['RESTRICTION_NOTICE']); add_structure('INDI:', 0, 9999, '<>'); add_element ('INDI:SEX', 0, 1, $TAG['SEX_VALUE']); add_structure('INDI:', 0, 9999, '<>'); add_structure('INDI:', 0, 9999, '<>'); add_structure('INDI:', 0, 9999, '<>'); add_structure('INDI:', 0, 9999, '<>'); add_structure('INDI:', 0, 9999, '<>'); add_element ('INDI:SUBM', 0, 9999, $TAG['XREF']); add_structure('INDI:', 0, 9999, '<>'); add_element ('INDI:ALIA', 0, 9999, $TAG['XREF']); add_element ('INDI:ANCI', 0, 9999, $TAG['XREF']); add_element ('INDI:DESI', 0, 9999, $TAG['XREF']); add_element ('INDI:RFN', 0, 1, $TAG['PERMANENT_RECORD_FILE_NUMBER']); add_element ('INDI:AFN', 0, 1, $TAG['ANCESTRAL_FILE_NUMBER']); add_element ('INDI:REFN', 0, 9999, $TAG['USER_REFERENCE_NUMBER']); add_element ('INDI:REFN:TYPE', 0, 1, $TAG['USER_REFERENCE_TYPE']); add_element ('INDI:RIN', 0, 1, $TAG['AUTOMATED_RECORD_ID']); add_structure('INDI:', 0, 1, '<>'); add_structure('INDI:', 0, 9999, '<>'); add_structure('INDI:', 0, 9999, '<>'); add_structure('INDI:', 0, 9999, '<>'); break; case '<>': add_element ($prefix.'BAPL', $min, $max, $TAG['NULL']); add_element ($prefix.'BAPL:DATE', 0, 1, $TAG['DATE_LDS_ORD']); add_element ($prefix.'BAPL:TEMP', 0, 1, $TAG['TEMPLE_CODE']); add_element ($prefix.'BAPL:PLAC', 0, 1, $TAG['PLACE_LIVING_ORDINANCE']); add_element ($prefix.'BAPL:STAT', 0, 1, $TAG['LDS_BAPTISM_DATE_STATUS']); add_element ($prefix.'BAPL:STAT:DATE', 1, 1, $TAG['CHANGE_DATE']); add_structure($prefix.'BAPL:', 0, 9999, '<>'); add_structure($prefix.'BAPL:', 0, 9999, '<>'); add_element ($prefix.'CONL', $min, $max, $TAG['NULL']); add_element ($prefix.'CONL:DATE', 0, 1, $TAG['DATE_LDS_ORD']); add_element ($prefix.'CONL:TEMP', 0, 1, $TAG['TEMPLE_CODE']); add_element ($prefix.'CONL:PLAC', 0, 1, $TAG['PLACE_LIVING_ORDINANCE']); add_element ($prefix.'CONL:STAT', 0, 1, $TAG['LDS_BAPTISM_DATE_STATUS']); add_element ($prefix.'CONL:STAT:DATE', 1, 1, $TAG['CHANGE_DATE']); add_structure($prefix.'CONL:', 0, 9999, '<>'); add_structure($prefix.'CONL:', 0, 9999, '<>'); add_element ($prefix.'ENDL', $min, $max, $TAG['NULL']); add_element ($prefix.'ENDL:DATE', 0, 1, $TAG['DATE_LDS_ORD']); add_element ($prefix.'ENDL:TEMP', 0, 1, $TAG['TEMPLE_CODE']); add_element ($prefix.'ENDL:PLAC', 0, 1, $TAG['PLACE_LIVING_ORDINANCE']); add_element ($prefix.'ENDL:STAT', 0, 1, $TAG['LDS_ENDOWMENT_DATE_STATUS']); add_element ($prefix.'ENDL:STAT:DATE', 1, 1, $TAG['CHANGE_DATE']); add_structure($prefix.'ENDL:', 0, 9999, '<>'); add_structure($prefix.'ENDL:', 0, 9999, '<>'); add_element ($prefix.'SLGC', $min, $max, $TAG['NULL']); add_element ($prefix.'SLGC:DATE', 0, 1, $TAG['DATE_LDS_ORD']); add_element ($prefix.'SLGC:TEMP', 0, 1, $TAG['TEMPLE_CODE']); add_element ($prefix.'SLGC:PLAC', 0, 1, $TAG['PLACE_LIVING_ORDINANCE']); add_element ($prefix.'SLGC:FAMC', 1, 1, $TAG['XREF']); add_element ($prefix.'SLGC:STAT', 0, 1, $TAG['LDS_CHILD_SEALING_DATE_STATUS']); add_element ($prefix.'SLGC:STAT:DATE', 1, 1, $TAG['CHANGE_DATE']); add_structure($prefix.'SLGC:', 0, 9999, '<>'); add_structure($prefix.'SLGC:', 0, 9999, '<>'); break; case '<>': add_element ($prefix.'SLGS', $min, $max, $TAG['NULL']); add_element ($prefix.'SLGS:DATE', 0, 1, $TAG['DATE_LDS_ORD']); add_element ($prefix.'SLGS:TEMP', 0, 1, $TAG['TEMPLE_CODE']); add_element ($prefix.'SLGS:STAT', 0, 1, $TAG['LDS_SPOUSE_SEALING_DATE_STATUS']); add_element ($prefix.'SLGS:STAT:DATE', 1, 1, $TAG['CHANGE_DATE']); add_structure($prefix.'SLGS:', 0, 9999, '<>'); add_structure($prefix.'SLGS:', 0, 9999, '<>'); break; case '<>': add_element ($prefix.'OBJE', $min, $max, $TAG['XREF']); // Old formats for objects not supported // add_element ($prefix.'OBJE', $min, $max, $TAG['NULL']); // add_element ($prefix.'OBJE:FILE', 1, 9999, $TAG['MULTIMEDIA_FILE_REFN']); // add_element ($prefix.'OBJE:FILE:MEDI', 0, 1, $TAG['MULTIMEDIA_FORMAT']); // add_element ($prefix.'OBJE:TITL', 0, 1, $TAG['DESCRIPTIVE_TITLE']); break; case '<>': add_element ($prefix.'OBJE', $min, $max, $TAG['NULL']); add_element ($prefix.'OBJE:FILE', 1, 9999, $TAG['MULTIMEDIA_FILE_REFN']); add_element ($prefix.'OBJE:FILE:FORM', 1, 1, $TAG['MULTIMEDIA_FORMAT']); add_element ($prefix.'OBJE:FILE:FORM:TYPE', 0, 1, $TAG['SOURCE_MEDIA_TYPE']); add_element ($prefix.'OBJE:FILE:TITL', 0, 1, $TAG['DESCRIPTIVE_TITLE']); add_element ($prefix.'OBJE:REFN', 0, 9999, $TAG['USER_REFERENCE_NUMBER']); add_element ($prefix.'OBJE:REFN:TYPE', 0, 1, $TAG['USER_REFERENCE_TYPE']); add_element ($prefix.'OBJE:RIN', 0, 1, $TAG['AUTOMATED_RECORD_ID']); add_structure($prefix.'OBJE:', 0, 1, '<>'); add_structure($prefix.'OBJE:', 0, 9999, '<>'); add_structure($prefix.'OBJE:', 0, 9999, '<>'); break; case '<>': add_element ($prefix.'NOTE', $min, $max, $TAG['SUBMITTER_TEXT']); add_element ($prefix.'NOTE:CONC', 0, 9999, $TAG['SUBMITTER_TEXT']); add_element ($prefix.'NOTE:CONT', 0, 9999, $TAG['SUBMITTER_TEXT']); add_element ($prefix.'NOTE:REFN', 0, 9999, $TAG['USER_REFERENCE_NUMBER']); add_element ($prefix.'NOTE:REFN:TYPE', 0, 1, $TAG['USER_REFERENCE_TYPE']); add_element ($prefix.'NOTE:RIN', 0, 1, $TAG['AUTOMATED_RECORD_ID']); add_structure($prefix.'NOTE:', 0, 1, '<>'); add_structure($prefix.'NOTE:', 0, 9999, '<>'); break; case '<>': add_element ($prefix.'NOTE', $min, $max, $TAG['XREF'].'|'.$TAG['SUBMITTER_TEXT']); add_element ($prefix.'NOTE:CONT', 0, 9999, $TAG['SUBMITTER_TEXT']); add_element ($prefix.'NOTE:CONC', 0, 9999, $TAG['SUBMITTER_TEXT']); break; case '<>': add_element ($prefix.'NPFX', $min, $max, $TAG['NAME_PIECE_PREFIX']); add_element ($prefix.'GIVN', 0, 1, $TAG['NAME_PIECE_GIVEN']); add_element ($prefix.'NICK', 0, 1, $TAG['NAME_PIECE_NICKNAME']); add_element ($prefix.'SPFX', 0, 1, $TAG['NAME_PIECE_SURNAME_PREFIX']); add_element ($prefix.'SURN', 0, 1, $TAG['NAME_PIECE_SURNAME']); add_element ($prefix.'NSFX', 0, 1, $TAG['NAME_PIECE_SUFFIX']); add_structure($prefix, 0, 9999, '<>'); add_structure($prefix, 0, 9999, '<>'); break; case '<>': add_element ($prefix.'NAME', $min, $max, $TAG['NAME_PERSONAL']); add_element ($prefix.'NAME:TYPE', 0, 1, $TAG['NAME_TYPE']); add_structure($prefix.'NAME:', 0, 1, '<>'); add_element ($prefix.'NAME:FONE', 0, 9999, $TAG['NAME_PHONETIC_VARIATION']); add_element ($prefix.'NAME:FONE:TYPE', 1, 1, $TAG['PHONETIC_TYPE']); add_structure($prefix.'NAME:FONE:', 0, 1, '<>'); add_element ($prefix.'NAME:ROMN', 0, 9999, $TAG['NAME_ROMANIZED_VARIATION']); add_element ($prefix.'NAME:ROMN:TYPE', 1, 1, $TAG['ROMANIZED_TYPE']); add_structure($prefix.'NAME:ROMN:', 0, 1, '<>'); break; case '<>': add_element ($prefix.'PLAC', $min, $max, $TAG['PLACE_NAME']); add_element ($prefix.'PLAC:FORM', 0, 1, $TAG['PLACE_HIERARCHY']); add_element ($prefix.'PLAC:FONE', 0, 9999, $TAG['PLACE_PHONETIC_VARIATION']); add_element ($prefix.'PLAC:FONE:TYPE', 1, 1, $TAG['PHONETIC_TYPE']); add_element ($prefix.'PLAC:ROMN', 0, 9999, $TAG['PLACE_ROMANIZED_VARIATION']); add_element ($prefix.'PLAC:ROMN:TYPE', 1, 1, $TAG['PHONETIC_TYPE']); add_element ($prefix.'PLAC:MAP', 0, 1, $TAG['NULL']); add_element ($prefix.'PLAC:MAP:LATI', 1, 1, $TAG['PLACE_LATITUDE']); add_element ($prefix.'PLAC:MAP:LONG', 1, 1, $TAG['PLACE_LONGITUDE']); add_structure($prefix.'PLAC:', 0, 9999, '<>'); break; case '<>': add_element ($prefix.'REPO', $min, $max, $TAG['NULL']); add_element ($prefix.'REPO:NAME', 1, 1, $TAG['NAME_OF_REPOSITORY']); add_structure($prefix.'REPO:', 0, 1, '<>'); add_structure($prefix.'REPO:', 0, 9999, '<>'); add_element ($prefix.'REPO:REFN', 0, 9999, $TAG['USER_REFERENCE_NUMBER']); add_element ($prefix.'REPO:REFN:TYPE', 0, 1, $TAG['USER_REFERENCE_TYPE']); add_element ($prefix.'REPO:RIN', 0, 1, $TAG['AUTOMATED_RECORD_ID']); add_structure($prefix.'REPO:', 0, 1, '<>'); break; case '<>': add_element ($prefix.'SOUR', $min, $max, $TAG['XREF']); add_element ($prefix.'SOUR:PAGE', 0, 1, $TAG['WHERE_WITHIN_SOURCE']); add_element ($prefix.'SOUR:EVEN', 0, 1, $TAG['EVENT_TYPE_CITED_FROM']); add_element ($prefix.'SOUR:EVEN:ROLE', 0, 1, $TAG['ROLE_IN_EVENT']); add_element ($prefix.'SOUR:DATA', 0, 1, $TAG['NULL']); add_element ($prefix.'SOUR:DATA:DATE', 0, 1, $TAG['ENTRY_RECORDING_DATE']); add_element ($prefix.'SOUR:DATA:TEXT', 0, 9999, $TAG['TEXT_FROM_SOURCE']); add_element ($prefix.'SOUR:DATA:TEXT:CONC', 0, 9999, $TAG['TEXT_FROM_SOURCE']); add_element ($prefix.'SOUR:DATA:TEXT:CONT', 0, 9999, $TAG['TEXT_FROM_SOURCE']); add_structure($prefix.'SOUR:', 0, 9999, '<>'); add_structure($prefix.'SOUR:', 0, 9999, '<>'); add_element ($prefix.'SOUR:QUAY', 0, 1, $TAG['CERTAINTY_ASSESSMENT']); break; case '<>': add_element ($prefix.'SOUR', $min, $max, $TAG['NULL']); add_element ($prefix.'SOUR:DATA', 0, 1, $TAG['NULL']); add_element ($prefix.'SOUR:DATA:EVEN', 0, 9999, $TAG['EVENTS_RECORDED']); add_element ($prefix.'SOUR:DATA:EVEN:DATE', 0, 1, $TAG['DATE_PERIOD']); add_element ($prefix.'SOUR:DATA:EVEN:PLAC', 0, 1, $TAG['SOURCE_JURISDICTION_PLACE']); add_element ($prefix.'SOUR:DATA:AGNC', 0, 1, $TAG['RESPONSIBLE_AGENCY']); add_structure($prefix.'SOUR:DATA:', 0, 9999, '<>'); add_element ($prefix.'SOUR:AUTH', 0, 1, $TAG['SOURCE_ORIGINATOR']); add_element ($prefix.'SOUR:AUTH:CONT', 0, 9999, $TAG['SOURCE_ORIGINATOR']); add_element ($prefix.'SOUR:AUTH:CONC', 0, 9999, $TAG['SOURCE_ORIGINATOR']); add_element ($prefix.'SOUR:TITL', 0, 1, $TAG['SOURCE_DESCRIPTIVE_TITLE']); add_element ($prefix.'SOUR:TITL:CONT', 0, 9999, $TAG['SOURCE_DESCRIPTIVE_TITLE']); add_element ($prefix.'SOUR:TITL:CONC', 0, 9999, $TAG['SOURCE_DESCRIPTIVE_TITLE']); add_element ($prefix.'SOUR:ABBR', 0, 1, $TAG['SOURCE_FILED_BY_ENTRY']); add_element ($prefix.'SOUR:PUBL', 0, 1, $TAG['SOURCE_PUBLICATION_FACTS']); add_element ($prefix.'SOUR:PUBL:CONT', 0, 9999, $TAG['SOURCE_PUBLICATION_FACTS']); add_element ($prefix.'SOUR:PUBL:CONC', 0, 9999, $TAG['SOURCE_PUBLICATION_FACTS']); add_element ($prefix.'SOUR:TEXT', 0, 1, $TAG['TEXT_FROM_SOURCE']); add_element ($prefix.'SOUR:TEXT:CONT', 0, 9999, $TAG['TEXT_FROM_SOURCE']); add_element ($prefix.'SOUR:TEXT:CONC', 0, 9999, $TAG['TEXT_FROM_SOURCE']); add_structure($prefix.'SOUR:', 0, 9999, '<>'); add_element ($prefix.'SOUR:REFN', 0, 9999, $TAG['USER_REFERENCE_NUMBER']); add_element ($prefix.'SOUR:REFN:TYPE', 0, 1, $TAG['USER_REFERENCE_TYPE']); add_element ($prefix.'SOUR:RIN', 0, 1, $TAG['AUTOMATED_RECORD_ID']); add_structure($prefix.'SOUR:', 0, 1, '<>'); add_structure($prefix.'SOUR:', 0, 9999, '<>'); add_structure($prefix.'SOUR:', 0, 9999, '<>'); break; case '<>': add_element ($prefix.'REPO', $min, $max, $TAG['XREF']); add_structure($prefix.'REPO:', 0, 9999, '<>'); add_element ($prefix.'REPO:CALN', 0, 9999, $TAG['SOURCE_CALL_NUMBER']); add_element ($prefix.'REPO:CALN:MEDI', 0, 1, $TAG['SOURCE_MEDIA_TYPE']); break; case '<>': add_element ($prefix.'FAMS', $min, $max, $TAG['XREF']); add_structure($prefix.'FAMS:', 0, 9999, '<>'); break; case '<>': add_element ($prefix.'SUBN', $min, $max, $TAG['NULL']); add_element ($prefix.'SUBN:SUBM', 0, 1, $TAG['XREF']); add_element ($prefix.'SUBN:FAMF', 0, 1, $TAG['NAME_OF_FAMILY_FILE']); add_element ($prefix.'SUBN:TEMP', 0, 1, $TAG['TEMPLE_CODE']); add_element ($prefix.'SUBN:ANCE', 0, 1, $TAG['GENERATIONS_OF_ANCESTORS']); add_element ($prefix.'SUBN:DESC', 0, 1, $TAG['GENERATIONS_OF_DESCENDANTS']); add_element ($prefix.'SUBN:ORDI', 0, 1, $TAG['ORDINANCE_PROCESS_FLAG']); add_element ($prefix.'SUBN:RIN', 0, 1, $TAG['AUTOMATED_RECORD_ID']); add_structure($prefix.'SUBN:', 0, 9999, '<>'); add_structure($prefix.'SUBN:', 0, 1, '<>'); break; case '<>': add_element ($prefix.'SUBM', $min, $max, $TAG['NULL']); add_element ($prefix.'SUBM:NAME', 1, 1, $TAG['SUBMITTER_NAME']); add_structure($prefix.'SUBM:', 0, 9999, '<>'); add_structure($prefix.'SUBM:', 0, 9999, '<>'); add_element ($prefix.'SUBM:LANG', 0, 3, $TAG['LANGUAGE_PREFERENCE']); add_element ($prefix.'SUBM:RFN', 0, 1, $TAG['SUBMITTER_REGISTERED_RFN']); add_element ($prefix.'SUBM:RIN', 0, 1, $TAG['AUTOMATED_RECORD_ID']); add_structure($prefix.'SUBM:', 0, 9999, '<>'); add_structure($prefix.'SUBM:', 0, 1, '<>'); break; } } // A GEDCOM file consists of the following level 0 elements add_structure('', 1, 1, '<
>'); add_structure('', 0, 1, '<>'); add_structure('', 0, 999999, '<>'); add_structure('', 0, 999999, '<>'); add_structure('', 0, 999999, '<>'); add_structure('', 0, 999999, '<>'); add_structure('', 0, 999999, '<>'); add_structure('', 0, 999999, '<>'); add_structure('', 0, 999999, '<>'); add_element ('TRLR', 1, 1, $TAG['NULL']); unset($TAG); // Save memory. //////////////////////////////////////////////////////////////////////////////// // Main program starts here. // Scan the file for lines containing XREFs and build up the tag hierarchy //////////////////////////////////////////////////////////////////////////////// $all_xrefs=array(); $used_xrefs=array(); $xref_links=array(); $curr_xref='HEAD'; $ged_level=array(); $ged_tag=array(); $handle=fopen($all_geds[$ged], 'r'); while (($value=fgets($handle))!==false) { $value=preg_replace('/[\r\n]+/', '', $value); if (preg_match('/^\s*(\d*)\s*(@[^@#]+@)?\s*(\S*)\s*(.*)/', $value, $match)) { $gedfile[]=$value; if ($match[1]=='0') { $curr_xref=$match[2]; $all_xrefs[$match[2].$match[3]]=true; } else { if (preg_match('/(FAMC|FAMS|HUSB|WIFE|CHIL)/', $match[3])) $xref_links[$curr_xref.$match[3].$match[4]]=true; if (isset($XREF_LINK[$match[3]])) $used_xrefs[$match[4].$XREF_LINK[$match[3]]]=true; else $used_xrefs[$match[4].$match[3]]=true; } } else echo '

Internal error: REGEXP failed on "', htmlspecialchars($value), '"

'; } fclose($handle); //////////////////////////////////////////////////////////////////////////////// // Check the file at a syntactic level, line-by-line //////////////////////////////////////////////////////////////////////////////// // Gedcom files are english, left-to-right, whatever the page language echo '

'; $num_lines=count($gedfile); // Ignore the Byte-Order-Mark on UTF files if ($num_lines>0) $gedfile[0]=preg_replace('/^'.WT_UTF8_BOM.'/', '', $gedfile[0]); $context=array('GEDCOM'); $curr_xref=''; foreach ($gedfile as $num=>$value) { preg_match('/^(\s*)(\d*)(\s*)(@[^@#]+@)?(\s*)(\S*)(\s?)(.*)/', $value, $match); $whitespace1=$match[1]; $tag_level =$match[2]; $whitespace2=$match[3]; $xref =$match[4]; $whitespace3=$match[5]; $tag =$match[6]; $whitespace4=$match[7]; $tag_data =$match[8]; // What sort of object would this tag point to if (isset($XREF_LINK[$tag])) $linked_rec=$XREF_LINK[$tag]; else $linked_rec=$tag; // Work out our current context $context[$tag_level]=$tag; $tmp=$context[0]; for ($i=1; $i<=$tag_level; ++$i) if (isset($context[$i])) $tmp.=':'.$context[$i]; // No errors initially $err=''; // Huge nested if/else contruct. Handle with care! if ($err_level>=$critical) { // CRITICAL CHECKS - links if ($tag=='') $err=missing(WT_I18N::translate('tag')); elseif ($tag_level=='') $err=missing(WT_I18N::translate('Level')); elseif (preg_match('/^(@[^#@:!]+@)$/', $tag_data)) { // exclude external/internal XREfs with :/! if (!isset($all_xrefs[$tag_data.$linked_rec])) $err=missing("0 $tag_data $linked_rec"); elseif ($tag_level=='1' && (($tag=='FAMS' ) && !isset($xref_links[$tag_data.'HUSB'.$curr_xref]) && !isset($xref_links[$tag_data.'WIFE'.$curr_xref]) || ($tag=='FAMC' ) && !isset($xref_links[$tag_data.'CHIL'.$curr_xref]) || ($tag=='HUSB' || $tag=='WIFE') && !isset($xref_links[$tag_data.'FAMS'.$curr_xref]) || ($tag=='CHIL' ) && !isset($xref_links[$tag_data.'FAMC'.$curr_xref]) )) $err=no_link(wt_href($XREF_LINK[$tag], $tag_data)); } if ($err_level>=$error && $err=='') { // ERROR CHECKS - tags if (!preg_match('/^[1-9]?[0-9]$/', $tag_level)) $err=invalid(WT_I18N::translate('Level')); elseif (!preg_match('/^[A-Z0-9_]{1,31}$/', $tag)) $err=invalid(WT_I18N::translate('tag')); elseif (strpos($tmp, '_')===false) { if (!isset($CONTEXT[$tmp])) $err=invalid(WT_I18N::translate('tag')); } // Check tags at level N+1 $count_plus_one=array(); if ($err=='') { for ($i=$num+1; $i<$num_lines; ++$i) { preg_match('/^\s*(\d*)\s*(@[^@#]+@)?\s*(\S*)/', $gedfile[$i], $m); if ($m[1]<=$tag_level) { break; } if ($m[1]==$tag_level+1) { if (isset($count_plus_one[$m[3]])) { $count_plus_one[$m[3]]++; } else { $count_plus_one[$m[3]]=1; } } } } // Check min/max number of sub-tags at level N+1 if ($err=='') { foreach ($count_plus_one as $tag_plus_one=>$count_plus1) { if (isset($CONTEXT[$tmp.':'.$tag_plus_one])) { if ($count_plus1 > $CONTEXT_MAX[$tmp.':'.$tag_plus_one]) { $err=too_many($tmp.':'.$tag_plus_one); } elseif ($count_plus1 < $CONTEXT_MIN[$tmp.':'.$tag_plus_one]) { $err=too_few($tmp.':'.$tag_plus_one); } } } } // Check for missing subordinate tag (ignore custom tags) if ($err=='' && isset($CONTEXT[$tmp])) { foreach ($CONTEXT_SUB[$tmp] as $sub_tag=>$full_sub_tag) { if ($CONTEXT_MIN[$full_sub_tag]>0 && !isset($count_plus_one[$sub_tag])) { $err=missing($full_sub_tag); } } } if ($err_level>=$warning && $err=='') { // WARNING CHECKS - data if ((strpos($tmp, '_')===false) && !preg_match('/^'.$CONTEXT[$tmp].'$/i', $tag_data)) { $err=invalid(WT_I18N::translate('data')); } elseif ($tag_level=='0' && $xref!='' && !isset($used_xrefs[$xref.$tag])) { $err=WT_I18N::translate('Nothing references this record'); } if ($err_level>=$info && $err=='') { // INFOMATIONAL CHECKS - spacing if ($whitespace1!='' || $whitespace2!=' ' || $whitespace3==' ' && $xref=='' || $whitespace4==' ' && $tag=='') { $err=invalid(WT_I18N::translate('spacing')); } } // info } // warning } // error } // critical ////////////////////////////////////////////////////////////////////////////// // Record our current context for error logging and future checks. ////////////////////////////////////////////////////////////////////////////// if ($tag_level=='0' && $tag!='') { $curr_xref=$xref; $curr_l0tag=$tag; } ////////////////////////////////////////////////////////////////////////////// // If an error was found, print it in its context ////////////////////////////////////////////////////////////////////////////// if ($err!='') { if (isset($last_err_num)) { if ($num-$last_err_num>2*$context_lines && $context_lines>0) echo '
';
			for ($i=max($num-$context_lines, $last_err_num+$context_lines+1); $i<$num; ++$i)
				printf("%07d  %s\n", $i+1, $gedfile[$i]);
		} else {
			echo '
';
			for ($i=max(0,$num-$context_lines); $i<$num; ++$i)
				printf("%07d  %s\n", $i+1, $gedfile[$i]);
		}
		printf("‎%07d[[%s]]‎  %s; ".WT_I18N::translate('see')." %s\n", $num+1, htmlspecialchars($gedfile[$num]), $err, wt_href($curr_l0tag, $curr_xref));
		flush();
		$last_err_num=$num;
	} else
		if (isset($last_err_num) && $num-$last_err_num<=$context_lines)
			printf("%07d  %s\n", $num+1, $gedfile[$num]);

}

if (isset($last_err_num)) {
	echo '
'; } else { echo WT_I18N::translate('No errors found at this level.'); } echo '
'; // language/direction/alignment