public static ParseResult <Image> Parse(GedcomLine first, ILineProvider lineProvider) { var image = new Image(); image.ID = ParserHelper.ParseID(first.GetFirstItem()).ToString(); var initialLevel = first.Level; GedcomLine line = default; ReadOnlySpan <char> currentRawLine; while ((currentRawLine = lineProvider.ReadLine()) != null) { line = ParserHelper.ParseLine(currentRawLine); if (line.Level == first.Level) { break; } var splitLine = line.GetFirstItem(); if (ParserHelper.Equals(splitLine, "TITL")) { var title = line.GetLineContent(4); image.Title = title.ToString(); } else if (ParserHelper.Equals(splitLine, "FILE")) { var filePath = line.GetLineContent(4); image.FilePath = filePath.ToString(); } } return(ParseResult.Create(image, line)); }
public static ParseResult <GedcomEvent> Parse(GedcomLine first, ILineProvider lineProvider) { GedcomEvent gedcomEvent = new GedcomEvent(); var initialLevel = first.Level; GedcomLine line = default; ReadOnlySpan <char> currentRawLine; while ((currentRawLine = lineProvider.ReadLine()).Length > 0) { line = ParserHelper.ParseLine(currentRawLine); if (line.Level <= first.Level) { break; } ReadOnlySpan <char> tag = line.GetFirstItem(); if (ParserHelper.Equals(tag, "DATE")) { // If checks we're parsing actual date and not // CREA or CHAN tags // TODO: should actually put CREA and CHAN into different parser if (line.Level == initialLevel + 1) { var dateContent = line.GetLineContent(4); gedcomEvent.Date = dateContent.Length == 0 ? null : dateContent.ToString(); } } else if (ParserHelper.Equals(tag, "PLAC")) { // If checks we're parsing actual date and not // CREA or CHAN tags // TODO: should actually put CREA and CHAN into different parser if (line.Level == initialLevel + 1) { var placContent = line.GetLineContent(4); gedcomEvent.Location = placContent.Length == 0 ? null : placContent.ToString(); } } } return(ParseResult.Create(gedcomEvent, line)); }
public static ParseResult <GedcomEvent> Parse(GedcomLine first, ILineProvider lineProvider) { GedcomEvent gedcomEvent = new GedcomEvent(); var initialLevel = first.Level; GedcomLine line = default; string currentRawLine; while ((currentRawLine = lineProvider.ReadLine()) != null) { line = ParserHelper.ParseLine(currentRawLine); if (line.Level <= first.Level) { break; } switch (line.GetTagOrRef()) { case "DATE": // If checks we're parsing actual date and not // CREA or CHAN tags // TODO: should actually put CREA and CHAN into different parser if (line.Level == initialLevel + 1) { gedcomEvent.Date = line.GetLineContent(); } break; case "PLAC": // If checks we're parsing actual date and not // CREA or CHAN tags // TODO: should actually put CREA and CHAN into different parser if (line.Level == initialLevel + 1) { gedcomEvent.Location = line.GetLineContent(); } break; } } return(ParseResult.Create(gedcomEvent, line)); }
public static ParseResult <Note> Parse(GedcomLine first, ILineProvider lineProvider) { string id = ParserHelper.ParseID(first.GetFirstItem()).ToString(); string text = null; var initialLevel = first.Level; GedcomLine line = default; ReadOnlySpan <char> currentRawLine; while ((currentRawLine = lineProvider.ReadLine()).Length > 0) { line = ParserHelper.ParseLine(currentRawLine); if (line.Level == first.Level) { break; } ReadOnlySpan <char> tag = line.GetFirstItem(); if (ParserHelper.Equals(tag, "CONT")) { string contText = line.GetLineContent(4).ToString(); text += Environment.NewLine + contText; } else if (ParserHelper.Equals(tag, "CONC")) { // TODO: is GenesReunited maintaining the trailing space? // If so, is this correct? string concText = line.GetLineContent(4).ToString(); text += concText; } } return(ParseResult.Create(new Note(id, text), line)); }
public static ParseResult <Note> Parse(GedcomLine first, ILineProvider lineProvider) { string id = ParserHelper.ParseID(first.GetTagOrRef()); string text = null; var initialLevel = first.Level; GedcomLine line = default; string currentRawLine; while ((currentRawLine = lineProvider.ReadLine()) != null) { line = ParserHelper.ParseLine(currentRawLine); if (line.Level == first.Level) { break; } switch (line.GetTagOrRef()) { case "CONT": string contText = line.GetLineContent(); text += Environment.NewLine + contText; break; case "CONC": // TODO: is GenesReunited maintaining the trailing space? // If so, is this correct? string concText = line.GetLineContent(); text += concText; break; } } return(ParseResult.Create(new Note(id, text), line)); }
public static ParseResult <Image> Parse(GedcomLine first, ILineProvider lineProvider) { var image = new Image(); image.ID = ParserHelper.ParseID(first.GetTagOrRef()); var initialLevel = first.Level; GedcomLine line = default; string currentRawLine; while ((currentRawLine = lineProvider.ReadLine()) != null) { line = ParserHelper.ParseLine(currentRawLine); if (line.Level == first.Level) { break; } switch (line.GetTagOrRef()) { case "TITL": var title = line.GetLineContent(); image.Title = title; break; case "FILE": var filePath = line.GetLineContent(); image.FilePath = filePath; break; } } return(ParseResult.Create(image, line)); }
public static ParseResult <GedcomHeader> Parse(GedcomLine first, ILineProvider lineProvider) { CurrentLevel currentLevel = CurrentLevel.None; var header = new GedcomHeader(); GedcomLine line = default; string currentRawLine; while ((currentRawLine = lineProvider.ReadLine()) != null) { line = ParserHelper.ParseLine(currentRawLine); if (line.Level == 0) { break; } if (line.Level == 1) { switch (line.GetTagOrRef()) { case "SOUR": currentLevel = CurrentLevel.Sour; break; case "GEDC": currentLevel = CurrentLevel.Gedc; break; case "CHAR": header.GedcomCharacterSet = line.GetLineContent(); break; } } else if (line.Level == 2) { if (currentLevel == CurrentLevel.Sour) { switch (line.GetTagOrRef()) { case "NAME": header.SourceName = line.GetLineContent(); break; case "VERS": header.SourceVers = line.GetLineContent(); break; case "CORP": header.SourceCorp = line.GetLineContent(); break; } } else if (currentLevel == CurrentLevel.Gedc) { if (line.GetTagOrRef() == "VERS") { header.GedcomVers = line.GetLineContent(); } } } } return(ParseResult.Create(header, line)); }
public static ParseResult <Family> Parse(GedcomLine first, ILineProvider lineProvider) { var family = new Family(); family.ID = ParserHelper.ParseID(first.GetFirstItem()).ToString(); bool inMarriage = false; var initialLevel = first.Level; GedcomLine line = default; ReadOnlySpan <char> currentRawLine; while ((currentRawLine = lineProvider.ReadLine()).Length > 0) { line = ParserHelper.ParseLine(currentRawLine); if (line.Level == first.Level) { break; } var tag = line.GetFirstItem(); if (ParserHelper.Equals(tag, "MARR")) { inMarriage = true; } else if (ParserHelper.Equals(tag, "DATE")) { if (inMarriage) // TODO: should have MARR parser { var date = line.GetLineContent(4); if (family.Marriage == null) { family.Marriage = new GedcomEvent(); } family.Marriage.Date = date.ToString(); } } else if (ParserHelper.Equals(tag, "PLAC")) { if (inMarriage) // Assume level + 1 is MARR { var place = line.GetLineContent(4); if (family.Marriage == null) { family.Marriage = new GedcomEvent(); } family.Marriage.Location = place.ToString(); } } else if (ParserHelper.Equals(tag, "HUSB")) { // Ignore any husband and wife information in the middle of a marriage tag. // Present for torture test files - and info redundant? // can have e.g. "2 HUSB", with no additional info var husbContent = line.GetLineContent(4); if (husbContent.Length > 0) { family.HusbandID = ParserHelper.ParseID(husbContent).ToString(); } } else if (ParserHelper.Equals(tag, "WIFE")) { var wifeContent = line.GetLineContent(4); // Ignore any husband and wife information in the middle of a marriage tag. // Present for torture test files - and info redundant? // can have e.g. "2 HUSB", with no additional info if (wifeContent.Length > 0) { family.WifeID = ParserHelper.ParseID(wifeContent).ToString(); } } else if (ParserHelper.Equals(tag, "CHIL")) { var childContent = line.GetLineContent(4); family.ChildIDs.Add(ParserHelper.ParseID(childContent).ToString()); } else { inMarriage = false; } } return(ParseResult.Create(family, line)); }
public static ParseResult <Individual> Parse(GedcomLine first, ILineProvider lineProvider) { var individual = new Individual(); individual.ID = ParserHelper.ParseID(first.GetTagOrRef()); GedcomLine line = default; string currentRawLine; var newLine = false; while (true) { // TODO: this loop is really messy, as some of the parsing // works on lines as retrieved from the parser, where some // other iterations call onto a sub-parser which return a final // line. Should split this logic if (!newLine) { currentRawLine = lineProvider.ReadLine(); if (currentRawLine == null) { break; } line = ParserHelper.ParseLine(currentRawLine); } newLine = false; if (line.Level == 0) { break; } switch (line.GetTagOrRef()) { case "NAME": if (individual.LastName != null || individual.FirstNames != null) { break; } ParseNames(line, individual); break; case "SEX": individual.Gender = (line.GetLineContent() == "M") ? Gender.Male : Gender.Female; break; case "FAMS": individual.FamilyIDSpouse = ParserHelper.ParseID(line.GetLineContent()); break; case "FAMC": individual.FamilyIDChild = ParserHelper.ParseID(line.GetLineContent()); break; case "OBJE": var objeContent = line.GetLineContent(); if (!string.IsNullOrEmpty(objeContent)) // TODO: test for this - currently don't support Images directly in Individual // should fix this { individual.ImageID = ParserHelper.ParseID(objeContent); } break; case "NOTE": string noteText = line.GetLineContent() ?? string.Empty; // My be an empty NOTE tag, but will be concatenated onto if (noteText.StartsWith("@")) { string noteId = ParserHelper.ParseID(noteText); individual.NoteID = noteId; } else { individual.Note = noteText; } break; case "CONT": string contText = line.GetLineContent() ?? string.Empty; individual.Note += Environment.NewLine + contText; break; case "CONC": // TODO: is GenesReunited maintaining the trailing space? // If so, is this correct? var concText = line.GetLineContent(); individual.Note += concText; break; case "BIRT": var birthParseResult = EventParser.Parse(line, lineProvider); if (individual.Birth == null) { individual.Birth = birthParseResult.Result; } line = birthParseResult.Line; newLine = true; break; case "DEAT": var deathParseResult = EventParser.Parse(line, lineProvider); if (individual.Death == null) { individual.Death = deathParseResult.Result; } line = deathParseResult.Line; newLine = true; break; case "BAPM": var baptismParseResult = EventParser.Parse(line, lineProvider); if (individual.Baptism == null) { individual.Baptism = baptismParseResult.Result; } line = baptismParseResult.Line; newLine = true; break; case "RESI": var residenceParseResult = EventParser.Parse(line, lineProvider); individual.Residences.Add(residenceParseResult.Result); line = residenceParseResult.Line; newLine = true; break; case "CENS": var censusParseResult = EventParser.Parse(line, lineProvider); individual.Census.Add(censusParseResult.Result); line = censusParseResult.Line; newLine = true; break; case "MARR": var marriageParseResult = EventParser.Parse(line, lineProvider); if (marriageParseResult.Result != null) { individual.Marriages.Add(marriageParseResult.Result); } line = marriageParseResult.Line; newLine = true; // TODO: cope with multiple marriage records // It seems that ancestry only outputs multiple marriage records in an individual // if there's conflicting information, not for multiple marriages // Multiple marriages for an individual are put into the FAMs tag break; //case "ENGA": // // TODO: // // individual.Engagement = EventParser.Parse(parserLinesEnga); // break; } if (line.Level == 0) { break; } } if (individual.LastName == null) { individual.LastName = string.Empty; } if (individual.FirstName == null) { individual.FirstName = string.Empty; } if (individual.FirstNames == null) { individual.FirstNames = string.Empty; } return(ParseResult.Create(individual, line)); }
public static ParseResult <Family> Parse(GedcomLine first, ILineProvider lineProvider) { var family = new Family(); family.ID = ParserHelper.ParseID(first.GetTagOrRef()); bool inMarriage = false; var initialLevel = first.Level; GedcomLine line = default; string currentRawLine; while ((currentRawLine = lineProvider.ReadLine()) != null) { line = ParserHelper.ParseLine(currentRawLine); if (line.Level == first.Level) { break; } switch (line.GetTagOrRef()) { case "MARR": { inMarriage = true; break; } case "DATE": if (inMarriage) // TODO: should have MARR parser { var date = line.GetLineContent(); if (family.Marriage == null) { family.Marriage = new GedcomEvent(); } family.Marriage.Date = date; } break; case "PLAC": if (inMarriage) // Assume level + 1 is MARR { var place = line.GetLineContent(); if (family.Marriage == null) { family.Marriage = new GedcomEvent(); } family.Marriage.Location = place; } break; case "HUSB": // Ignore any husband and wife information in the middle of a marriage tag. // Present for torture test files - and info redundant? // can have e.g. "2 HUSB", with no additional info var contentHusb = line.GetLineContent(); if (!string.IsNullOrEmpty(contentHusb)) { family.HusbandID = ParserHelper.ParseID(contentHusb); } break; case "WIFE": // Ignore any husband and wife information in the middle of a marriage tag. // Present for torture test files - and info redundant? // can have e.g. "2 HUSB", with no additional info var contentWife = line.GetLineContent(); if (!string.IsNullOrEmpty(contentWife)) { family.WifeID = ParserHelper.ParseID(contentWife); } break; case "CHIL": family.ChildIDs.Add(ParserHelper.ParseID(line.GetLineContent())); break; default: inMarriage = false; break; } } return(ParseResult.Create(family, line)); }
public static ParseResult <Individual> Parse(GedcomLine first, ILineProvider lineProvider) { var individual = new Individual(); individual.ID = ParserHelper.ParseID(first.GetFirstItem()).ToString(); GedcomLine line = default; ReadOnlySpan <char> currentRawLine; var newLine = false; while (true) { // TODO: this loop is really messy, as some of the parsing // works on lines as retrieved from the parser, where some // other iterations call onto a sub-parser which return a final // line. Should split this logic if (!newLine) { currentRawLine = lineProvider.ReadLine(); if (currentRawLine == null) { break; } line = ParserHelper.ParseLine(currentRawLine); } newLine = false; if (line.Level == 0) { break; } var tag = line.GetFirstItem(); if (ParserHelper.Equals(tag, "NAME") && individual.LastName == null && individual.FirstNames == null) { ParseNames(line, individual); } else if (ParserHelper.Equals(tag, "SEX")) { individual.Gender = ParserHelper.Equals(line.GetLineContent(3), "M") ? Gender.Male : Gender.Female; } else if (ParserHelper.Equals(tag, "FAMS")) { individual.FamilyIDSpouse = ParserHelper.ParseID(line.GetLineContent(4)).ToString(); } else if (ParserHelper.Equals(tag, "FAMC")) { individual.FamilyIDChild = ParserHelper.ParseID(line.GetLineContent(4)).ToString(); } else if (ParserHelper.Equals(tag, "OBJE")) { var content = line.GetLineContent(4); if (content.Length > 0) { individual.ImageID = ParserHelper.ParseID(content).ToString(); } } else if (ParserHelper.Equals(tag, "NOTE")) { var noteContent = line.GetLineContent(4); if (noteContent.Length > 0) { if (noteContent[0] == '@') { individual.NoteID = ParserHelper.ParseID(noteContent).ToString(); } else { individual.Note = noteContent.ToString(); } } } else if (ParserHelper.Equals(tag, "CONT")) { var contContent = line.GetLineContent(4); individual.Note += Environment.NewLine + contContent.ToString(); } else if (ParserHelper.Equals(tag, "CONC")) { // TODO: is GenesReunited maintaining the trailing space? // If so, is this correct? var concContent = line.GetLineContent(4); if (concContent.Length > 0) { individual.Note += concContent.ToString(); } } else if (ParserHelper.Equals(tag, "BIRT")) { var birthParseResult = EventParser.Parse(line, lineProvider); if (individual.Birth == null) { individual.Birth = birthParseResult.Result; } line = birthParseResult.Line; newLine = true; } else if (ParserHelper.Equals(tag, "DEAT")) { var deathParseResult = EventParser.Parse(line, lineProvider); if (individual.Death == null) { individual.Death = deathParseResult.Result; } line = deathParseResult.Line; newLine = true; } else if (ParserHelper.Equals(tag, "BAPM")) { var baptismParseResult = EventParser.Parse(line, lineProvider); if (individual.Baptism == null) { individual.Baptism = baptismParseResult.Result; } line = baptismParseResult.Line; newLine = true; } else if (ParserHelper.Equals(tag, "RESI")) { var residenceParseResult = EventParser.Parse(line, lineProvider); individual.Residences.Add(residenceParseResult.Result); line = residenceParseResult.Line; newLine = true; } else if (ParserHelper.Equals(tag, "CENS")) { var censusParseResult = EventParser.Parse(line, lineProvider); individual.Census.Add(censusParseResult.Result); line = censusParseResult.Line; newLine = true; } else if (ParserHelper.Equals(tag, "MARR")) { var marriageParseResult = EventParser.Parse(line, lineProvider); if (marriageParseResult.Result != null) { individual.Marriages.Add(marriageParseResult.Result); } line = marriageParseResult.Line; newLine = true; // TODO: cope with multiple marriage records // It seems that ancestry only outputs multiple marriage records in an individual // if there's conflicting information, not for multiple marriages // Multiple marriages for an individual are put into the FAMs tag } //case "ENGA": // // TODO: // // individual.Engagement = EventParser.Parse(parserLinesEnga); // break; if (line.Level == 0) { break; } } if (individual.LastName == null) { individual.LastName = string.Empty; } if (individual.FirstName == null) { individual.FirstName = string.Empty; } if (individual.FirstNames == null) { individual.FirstNames = string.Empty; } return(ParseResult.Create(individual, line)); }
public static ParseResult <GedcomHeader> Parse(GedcomLine first, ILineProvider lineProvider) { CurrentLevel currentLevel = CurrentLevel.None; var header = new GedcomHeader(); GedcomLine line = default; ReadOnlySpan <char> currentRawLine; while ((currentRawLine = lineProvider.ReadLine()).Length > 0) { line = ParserHelper.ParseLine(currentRawLine); if (line.Level == 0) { break; } if (line.Level == 1) { var tag = line.GetFirstItem(); if (ParserHelper.Equals(tag, "SOUR")) { currentLevel = CurrentLevel.Sour; } else if (ParserHelper.Equals(tag, "GEDC")) { currentLevel = CurrentLevel.Gedc; } else if (ParserHelper.Equals(tag, "CHAR")) { header.GedcomCharacterSet = line.GetLineContent(4).ToString(); } } else if (line.Level == 2) { if (currentLevel == CurrentLevel.Sour) { var tag = line.GetFirstItem(); if (ParserHelper.Equals(tag, "NAME")) { header.SourceName = line.GetLineContent(4).ToString(); } else if (ParserHelper.Equals(tag, "VERS")) { header.SourceVers = line.GetLineContent(4).ToString(); } else if (ParserHelper.Equals(tag, "CORP")) { header.SourceCorp = line.GetLineContent(4).ToString(); } } else if (currentLevel == CurrentLevel.Gedc) { if (ParserHelper.Equals(line.GetFirstItem(), "VERS")) { header.GedcomVers = line.GetLineContent(4).ToString(); } } } } return(ParseResult.Create(header, line)); }
public void Parse(ILineProvider lineProvider) { GedcomLine lastLine = default; var firstRawLine = lineProvider.ReadLine(); if (firstRawLine == null) { throw new InvalidOperationException("File empty"); } var firstLine = ParserHelper.ParseLine(firstRawLine); if (firstLine.Level != 0 && !ParserHelper.Equals(firstLine.GetFirstItem(), "HEAD")) { throw new InvalidOperationException("GEDCOM Header Not Found"); } var gedcomHeaderParse = HeaderParser.Parse(firstLine, lineProvider); _headerCallback?.Invoke(gedcomHeaderParse.Result); var newLine = gedcomHeaderParse.Line; lastLine = newLine; while (newLine.LineContent.Length > 0) { var content = newLine.GetLineContent(); if (content.Length == 0) { var unrecognisedRawLine = lineProvider.ReadLine(); if (unrecognisedRawLine != null) { newLine = ParserHelper.ParseLine(unrecognisedRawLine); lastLine = newLine; } else { newLine = default; } continue; } var unknown = false; if (ParserHelper.Equals(content, "INDI")) { var individualParseResult = IndividualParser.Parse(newLine, lineProvider); _individualCallback?.Invoke(individualParseResult.Result); newLine = individualParseResult.Line; lastLine = newLine; } else if (ParserHelper.Equals(content, "FAM")) { var familyParseResult = FamilyParser.Parse(newLine, lineProvider); _familyCallback?.Invoke(familyParseResult.Result); newLine = familyParseResult.Line; lastLine = newLine; } else if (ParserHelper.Equals(content, "NOTE")) { var noteParseResult = NoteParser.Parse(newLine, lineProvider); _noteCallback?.Invoke(noteParseResult.Result); newLine = noteParseResult.Line; lastLine = newLine; } else if (ParserHelper.Equals(content, "OBJE")) { var objParserResult = ObjectParser.Parse(newLine, lineProvider); _imageCallback?.Invoke(objParserResult.Result); newLine = objParserResult.Line; lastLine = newLine; } else { var unrecognisedRawLine = lineProvider.ReadLine(); if (unrecognisedRawLine != null) { newLine = ParserHelper.ParseLine(unrecognisedRawLine); lastLine = newLine; } else { newLine = default; } unknown = true; } if (unknown) { continue; } } if (lastLine.LineContent.Length == 0) { throw new InvalidOperationException("file contains no content"); } if (lastLine.Level != 0 || !ParserHelper.Equals(lastLine.GetFirstItem(), "TRLR")) { throw new InvalidOperationException("GEDCOM TRLR not found"); } }