Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Gedcom-Datei parsen (https://www.delphipraxis.net/183093-gedcom-datei-parsen.html)

hansklok 11. Dez 2014 01:05

Gedcom-Datei parsen
 
Hallo,

ich schreibe heute, da ich mir von der Community meiner alten Lieblingsprogrammiersprache Hilfe erhoffe, die mir die Kollegen des aktuellen Frameworks "Xojo" nicht geben können. An sich geht es um einen Algorithmus, deswegen ist die Plattform egal.

Was soll gepasst werden?

Eine Gedcom-Datei. Gedcom ist eine Textdatei, ein Format mit der Endung ".ged", in der Ahnenforscher Ihre Daten zum Stammbaum sichern können. Sie enthält Hauptobjekte (INDI, FAM, SOUR, OBJ, NOTE), die mit durch eine "0" am Zeilenanfang gekennzeichnet sind, und Unterobjekte (z.B. DATE, EVEN, PLAC etc.), die mit "1" oder größer gekennzeichnet werden.

Ich möchte eine Anwendung erstellen, die bestehende Gedcom-Dateien einlesen kann, um so mit den Daten zu arbeiten.

Wie?

Mein Gedanke war folgender: Erst einmal die Datei einlesen. Zum Beispiel in eine Stringlist. Anschließend alle Zeilen durchlaufen. Sollte die Zeile ein Hauptobjekt kennzeichnen, so soll die Zeilennummer als Anfangszeile in einer Variable gespeichert werden. Nennen wir sie A. Anschließend geht die Schleife weiter, bis zum nächsten Hauptobjekt. Nun soll in Variable B die Zeilennummer vor dem neuen Hauptobjekt gespeichert werden (B = Zeilennummer -1)

Haben A und B einen Wert, sollen diese als TPoint in einer Objektliste gespeichert werden.

Später, wenn die Springlist durchgelaufen ist, sollte man eine Liste haben, die alle Hauptobjekte, oder z.b. nur Personen enthält.
Für jeden Eintrag hat man nun die Start- und die Endzeilennummer und kann nun ebenfalls in einer Schleife jedes Objekt einzeln passen.

Darum gehts.

Was?

Ich suche Hilfe für den Algorithmus, der an sich sehr einfach sein sollte. Ich fände klasse, wenn man konzeptionelle Gedanken austauschen würde und/oder gemeinsam ein Strukturramm für diesen ersten Schritt zum einlesen einer Gedcom-Datei macht.

Wichtig: Das Xoxo-Framework bietet keine StringStreams.

Delphi-Quellcode:
procedure Parse(Gedcom As Stringlist)
var
  AktuelleZeile: String;
  AktuellesObjektName, AktuellesObjekt: String; // INDI, FAM, SOUR, OBJ, NOTE
  i, Start, Ende: Integer;
  istObjekt: Boolean = False;
begin
  for i:=1 to Gedcom.Count do
  begin
    AktuelleZeile:= Gedcom.Items[i];
    if LeftStr(AktuelleZeile, 1) = "0" then  
        AktuellesObjektName = Copy(AktuelleZeile, 3, 4);
        AktuellesObjektName = Trim(AktuellesObjektName);
        // solange diese nicht der Header ist
        if AktuellesObjektName <> "HEAD" then
          // Typ auslesen (INDI, FAM etc.)
          AktuellesObjekt = RightStr(AktuelleZeile, 4);
          AktuellesObjekt = Trim(AktuellesObjekt);
          case AktuellesObjekt of
            "INDI":
              begin
                if istObjekt then
                  B = i-1
                  istObjekt = False
                  // an dieser Stelle würde ich nun einem Point A und B zuweisen und das Objekt in einer Liste speichern
                else
                  A = i;
                  istObjekt = True
                end;
              end;
          end;
        end;
    end;
  end;
end;
Das war so ein erster Gedankenansatz. Ich hoffe, ihr konntet mir folgen.

Eines ist noch zu bedenken: Das Ende einer Gedcom-Datei wird ebenfalls mit einer 0 am Beginn gekennzeichnet ("0 TRLR"). Sollte istObjekt = True sein, muss als B Gedcom.Count-1 gesetzt werden.

Ich freue mich über einen regen Austausch.
Gute Nacht!

Perlsau 11. Dez 2014 02:41

AW: Gedcom-Datei parsen
 
Mir ist nicht so recht klargeworden, welche Hilfe du erwartest. Die Vorgehensweise zum Parsen der genannten Textdatei hast du doch bereits ausführlich beschrieben. Woran hapert es also noch? Funktioniert dein Code nicht? Erhältst du Fehlermeldungen? Wenn ja, welche?

Auch deinen Hinweis, daß das Xoxo-Framework keine StringStreams biete, verstehe ich nicht so ganz: Inwiefern ist das ausschlaggebend, wenn du doch gar nicht mit diesem Framework arbeiten willst, sondern lediglich mit der bezeichneten Textdatei?

TiGü 11. Dez 2014 09:37

AW: Gedcom-Datei parsen
 
Ist das jetzt nur für dich als Spielerei gedacht oder soll das ein ernsthaftes Produkt werden?
Bei so übermächtigen Konkurrenten wie MyHeritage braucht ihr schon ein dickes Alleinstellungsmerkmal, um gegenüber denen zu bestehen.

CCRDude 11. Dez 2014 10:11

AW: Gedcom-Datei parsen
 
Ich glaube, er hat nicht gesagt, dass er nicht mit dem Framework arbeiten möchte, sondern dass es egal sei, weil es nur um den Algorithmus und nicht die konkrete Implementierung gehe.
Sprich: er will Hilfe zum Algorithmus, und meint auch hier gut aufgehoben zu sein, obwohl wir Pascal sprechen :)

Zur Idee an sich: Zeilennummern merken wird sehr komplex. Was, wenn einer Person ein Feld hinzugefügt wird? Dann müssen alle Indizes danach angepasst werden. Ditto umgekehrt für Löschen.

Zum Parsen Personenblöcke übergeben mag noch gehen.
Pro Personenobjekt den Personenblock im Speicher halten auch, um unbekannte Felder uminterpretiert mitschleifen zu können.
Aber globale Indizes halte ich für zu unnötig umständlich.

Eine alternative Idee für das Umgehen mit dateiweiten Indizes wäre, jede Zeile als Objekt zu betrachten, denn Zeiger wären im Gegensatz zu Indizes bei Einfügeoperationen etc. stabil.

TiGü 11. Dez 2014 10:57

AW: Gedcom-Datei parsen
 
Ich würde mich einfach mal durch die Quelltexte dieser Open Source Projekte lesen:

http://sourceforge.net/directory/hom...ently-updated/

Die müssen ja auch alle irgendwie die GEDCOM-Datei parsen.

Dejan Vu 11. Dez 2014 12:12

AW: Gedcom-Datei parsen
 
Das sieht doch ganz wie eine Baumstruktur aus. Klar, wenn der Level (erste Ziffer) größer wird, hängt ein Kind dran. Wird er wieder kleiner, ist es ein weiterer Knoten im letzten Knoten des gleichen Levels. Nicht weiter wild, das einzulesen. Ich glaube, die Notation heißt 'Infix' (im Gegensatz zu Postfix oder Prefix)

Und es ist auch nicht weiter wild, das wieder abzuspeichern (Wieder Infix).
Ich würde mir also keine Gedanken darüber machen, die einzelnen Zeilennummern mitzuspeichern, denn sobald Du irgendwo etwas umsortiertst, entfernst oder hinzupackst, stimmten die Nummern ja nicht mehr.

Ich würde mir also eine Klasse für einen abstrakten Knoten definieren und davon die einzelnen Datentypen/Knotentypen ableiten (INDI, SOUR etc.)

Ein Knoten ist ein Ding mit Nutzdaten und eine Liste von Unterknoten. Die Nutzdaten ist Text, Datum, ein Dokument vielleicht, ein Bild(?) etc.

Xojo kann Klassen? Wenn ja: Fein. Wenn nicht. Dann... Oh je, wie war das doch gleich? Ach ja, wir bauen uns dann selbst einen Baum zusammen. Auf abstrakte Knoten etc. müssen wir dann eben pfeifen und alles über Arrays abbilden.

hansklok 11. Dez 2014 13:08

AW: Gedcom-Datei parsen
 
Zitat:

Zitat von Perlsau (Beitrag 1282977)
Mir ist nicht so recht klargeworden, welche Hilfe du erwartest. Die Vorgehensweise zum Parsen der genannten Textdatei hast du doch bereits ausführlich beschrieben. Woran hapert es also noch?

Es geht um den konzeptionellen Gedanken für einen Algorithmus, also die Performance, da ja doch etliche Stringelemente pro Objekt ausgelesen werden müssen.
Zitat:

Zitat von TiGü (Beitrag 1283014)
Ist das jetzt nur für dich als Spielerei gedacht oder soll das ein ernsthaftes Produkt werden?
Bei so übermächtigen Konkurrenten wie MyHeritage braucht ihr schon ein dickes Alleinstellungsmerkmal, um gegenüber denen zu bestehen.

Ja, es ist eine private "Spielerei". Ich möchte meine Daten in eine spezielle Form bringen, die mir kein auf dem Markt befindliches Produkt so bietet und der Aufwand wird sich lohnen. Ich habe viel Zeit damit verbracht nach dem zu suchen, was ich will und habe es nicht gefunden.
Zitat:

Zitat von TiGü (Beitrag 1283034)
Ich würde mich einfach mal durch die Quelltexte dieser Open Source Projekte lesen:

http://sourceforge.net/directory/hom...ently-updated/

Die müssen ja auch alle irgendwie die GEDCOM-Datei parsen.

Ja, das habe ich schon getan. Für mich war aber bisher der richtige Ansatz noch nicht dabei.
Zitat:

Zitat von Dejan Vu (Beitrag 1283050)
Xojo kann Klassen? Wenn ja: Fein. Wenn nicht. Dann... Oh je, wie war das doch gleich? Ach ja, wir bauen uns dann selbst einen Baum zusammen. Auf abstrakte Knoten etc. müssen wir dann eben pfeifen und alles über Arrays abbilden.

Und ob Xojo Klassen kann und zwar klasse ;) Die Sache mit dem Baum ist, und da kenne ich mich noch zu wenig aus. Vom Verständnis her.

Mit der Notation "Infix" kann ich leider nichts anfangen. Was ist das?

Dejan Vu 11. Dez 2014 15:08

AW: Gedcom-Datei parsen
 
Infix bedeutet beim Aufzählen aller Knoten eines Baumes: Erst 'mich', dann meine Kinder.
Prefix bedeutet (beim binären Baum): Erst linkes Kind, dann mich, dann rechtes Kind
Postfix 'erst rechts, dann ich, dann links'
Vielleicht war ich zu voreilig, und es gibt Pre- und Postfix-Notation bei t-ären(t>2) Bäumen gar nicht. (t-ärer Baum: Jeder Knoten kann max t Kinder haben).

Beim Aufzählen (und damit beim *erzeugen* der GEDCOM-Datei) würde man in etwa so vorgehen:
Code:
print-gedcom (node, level):
  print level, node.type, node.description
  for each child in node.children
    print-gedcom(child, level + 1)
und der Aufruf startet mit
Code:
  foreach node in root-nodes
    print-gedcom (node, 0)
Wie Du siehst, haben wir es hier mit einer rekursiven Datenstruktur zu tun, d.h. die Klasse 'Knoten' beinhaltet widerum 'Knoten' (nämlich die Liste der Kindknoten).

Mal das mal auf: Oben die Wurzel (hier: Level: -1)
darunter alle Hauptknoten (Level 0)
Unter jeden Hauptknoten kommen seine Unterknoten (Level 1)
und unter jeden Unterknoten (level k) wieder sein Unterknoten (Level k+1)
usw.

hansklok 11. Dez 2014 15:59

AW: Gedcom-Datei parsen
 
Zitat:

Zitat von Dejan Vu (Beitrag 1283090)
Vielleicht war ich zu voreilig, und es gibt Pre- und Postfix-Notation bei t-ären(t>2) Bäumen gar nicht. (t-ärer Baum: Jeder Knoten kann max t Kinder haben).

Dankeschön. Genauso ist es, eine Person kann 0..* Kinder haben.

Die Wurzel ist immer das erste INDI-Record eine Gedcom-Datei (z.B. "0 @I1@ INDI").

So richtig hilft mir der Gedankenansatz nicht weiter ;)

Sir Rufo 11. Dez 2014 16:17

AW: Gedcom-Datei parsen
 
Wenn schon, dann solltest du die ganze Datei parsen. Dann beginnt es schon mal beim HEAD. Aber das ist schon der erste Knoten, die wirkliche Root-Node ist die Datei selber.

Die Zeile fängt immer mit einer Zahl an und die referenziert auf den Parent im aktuellen Kontext.

Du brauchst also schon mal ein Konstrukt, wo du immer auf die aktuelle Parents zugreifen kannst.
Code:
0 ...
Delphi-Quellcode:
// Node einfügen
AddNode( TNode.Create( GetParent( 0 ) );
// diese Node wird ab nun bei GetParent( 1 ) zurückgeliefert
// GetParent( n ) mit n > 1 liefert nun eine Exception!
Code:
1 ...
2 ...
3 ...
1 ...
Delphi-Quellcode:
AddNode( TNode.Create( GetParent( 1 ) );
AddNode( TNode.Create( GetParent( 2 ) );
AddNode( TNode.Create( GetParent( 3 ) );

AddNode( TNode.Create( GetParent( 1 ) );
// Ab nun kann man nicht mehr auf Parent 2/3 zugreifen
Das würde ich zunächst umsetzen. Wenn das funktioniert, dann weitere Ableitungen von der Node-Basisklasse erstellen und spezialisieren.

TiGü 11. Dez 2014 16:22

AW: Gedcom-Datei parsen
 
Zitat:

Zitat von hansklok (Beitrag 1283102)
So richtig hilft mir der Gedankenansatz nicht weiter ;)

Was ist denn dein konkretes Problem?
Suchst du nach der passenden Baum- und/oder Klassenstruktur?

hansklok 11. Dez 2014 16:42

AW: Gedcom-Datei parsen
 
Zitat:

Zitat von TiGü (Beitrag 1283106)
Zitat:

Zitat von hansklok (Beitrag 1283102)
So richtig hilft mir der Gedankenansatz nicht weiter ;)

Was ist denn dein konkretes Problem?
Suchst du nach der passenden Baum- und/oder Klassenstruktur?

Die Klassenstruktur habe ich. Ich habe sie nach der Gedcom 5.51 Definition erstellt.

Das war an sich auch nicht das Problem, da ich ja nun die Datenstruktur/Modell habe. Es geht einzig und allein darum, wie ich eine bestehende Gedcom-Datei schnell einlesen kann. Und ich befürchte, dass das bei den ganzen Stringoperationen und bei Gedcom-Dateien mit 10000 Personen und/oder Familien und mehr etc. gar nicht so einfach ist, einen guten, schnellen Algorithmus zum parsen zu schreiben.

Sir Rufo 11. Dez 2014 17:16

AW: Gedcom-Datei parsen
 
Hier mal so ein Minimalprogramm zum Veranschaulichen
Delphi-Quellcode:
program dp_183093;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.Generics.Collections,
  System.SysUtils;

type
  TNode = class
  private
    FParent: TNode;
    FChildren: TList<TNode>;
    function GetLastChild: TNode;
    function GetChildCount: Integer;
    function GetChild( Index: Integer ): TNode;
  public
    constructor Create( AParent: TNode );
    destructor Destroy; override;

    procedure AddChild( ANode: TNode );

    property ChildCount: Integer read GetChildCount;
    property Children[Index: Integer]: TNode read GetChild;

    property Parent: TNode read FParent;
    property LastChild: TNode read GetLastChild;
  end;

  TGedFile = class( TNode )
  private
    function GetParent( Index: Integer ): TNode;
  public
    constructor Create( AValues: TArray<Integer> );
  end;

  { TNode }

procedure TNode.AddChild( ANode: TNode );
begin
  if Assigned( ANode.Parent ) and ( ANode.Parent <> nil )
  then
    raise Exception.Create( 'Fehlermeldung' );

  ANode.FParent := Self;

  if not FChildren.Contains( ANode )
  then
    FChildren.Add( ANode );
end;

constructor TNode.Create( AParent: TNode );
begin
  inherited Create;
  FChildren := TObjectList<TNode>.Create;
  if Assigned( AParent )
  then
    AParent.AddChild( Self );
end;

destructor TNode.Destroy;
begin
  FChildren.Free;
  inherited;
end;

function TNode.GetChild( Index: Integer ): TNode;
begin
  Result := FChildren[Index];
end;

function TNode.GetChildCount: Integer;
begin
  Result := FChildren.Count;
end;

function TNode.GetLastChild: TNode;
begin
  Result := FChildren.Last;
end;

{ TGedFile }

constructor TGedFile.Create( AValues: TArray<Integer> );
var
  LValue: Integer;
begin
  inherited Create( nil );

  for LValue in AValues do
    begin
      TNode.Create( GetParent( LValue ) );
    end;
end;

function TGedFile.GetParent( Index: Integer ): TNode;
begin
  Result := Self;
  while Index > 0 do
    begin
      if not Assigned( Result )
      then
        raise Exception.Create( 'Fehlermeldung' );
      Result := Result.LastChild;
      Dec( Index );
    end;
end;

procedure OutputNode( ANode: TNode; ALevel: Integer = 0 );
var
  LIdx: Integer;
begin
  Write( '':ALevel, ANode.ToString );
  if ALevel > 0
  then
    Write( ' (', ALevel - 1, ')' );
  WriteLn;
  for LIdx := 0 to ANode.ChildCount - 1 do
    OutputNode( ANode.Children[LIdx], ALevel + 1 );
end;

procedure Main;
var
  LFile: TGedFile;
begin
  LFile := TGedFile.Create( TArray<Integer>.Create( 0, 1, 2, 3, 1, 1, 1, 2, 3, 3, 3, 3 ) );
  try
    OutputNode( LFile );
  finally
    LFile.Free;
  end;
end;

begin
  try
    Main;
  except
    on E: Exception do
      WriteLn( E.ClassName, ': ', E.Message );
  end;
  ReadLn;

end.
Ausgabe ist dann wie folgt
Code:
TGedFile
 TNode (0)
  TNode (1)
   TNode (2)
    TNode (3)
  TNode (1)
  TNode (1)
  TNode (1)
   TNode (2)
    TNode (3)
    TNode (3)
    TNode (3)
    TNode (3)

TiGü 11. Dez 2014 17:28

AW: Gedcom-Datei parsen
 
Zitat:

Zitat von hansklok (Beitrag 1283111)
Und ich befürchte, dass das bei den ganzen Stringoperationen und bei Gedcom-Dateien mit 10000 Personen und/oder Familien und mehr etc. gar nicht so einfach ist, einen guten, schnellen Algorithmus zum parsen zu schreiben.

Dann dauert das eben ein bisschen beim Einlesen.
Wie oft man das für eine GEDCOM-Datei? => Einmal!
Das reine GEDCOM auslesen ist ja nicht das Problem, oder?

Viel schwieriger stelle ich mir vor, die logische Verknüpfung und Visualisierung hinzugekommen.
Meine Ur-ur-ur-Großeltern waren beispielsweise entfernte Cousins und hatten einen gemeinsamen Ur-ur- bzw. Ur-ur-ur-Großvater.
Wie erkennt man solche "geschlossenen Kreise" im Stammbaum?
Gerade bei 10.000 Personen, die sonst wie miteinander verwandt sein können, hast du zwangsläufig die unmöglichsten Konstellationen.

hansklok 11. Dez 2014 18:33

AW: Gedcom-Datei parsen
 
[QUOTE=TiGü;1283119]
Zitat:

Zitat von hansklok (Beitrag 1283111)
Viel schwieriger stelle ich mir vor, die logische Verknüpfung und Visualisierung hinzugekommen.
Meine Ur-ur-ur-Großeltern waren beispielsweise entfernte Cousins und hatten einen gemeinsamen Ur-ur- bzw. Ur-ur-ur-Großvater.
Wie erkennt man solche "geschlossenen Kreise" im Stammbaum?
Gerade bei 10.000 Personen, die sonst wie miteinander verwandt sein können, hast du zwangsläufig die unmöglichsten Konstellationen.

Genau das ist der Grund, warum ich mich so schwer tue, alles in einer Binärbaum-Struktur unterzubringen.

Die Personen/Familien werden alle in einer eigenen Liste gespeichert. Auf sie zugreifen kann man über deren UUID. Dann ist es auch möglich Spezialfälle wie Inzucht oder Cousin- & Cousinenehen darzustellen.

Sir Rufo 11. Dez 2014 18:50

AW: Gedcom-Datei parsen
 
Die GEDCOM-Datei ist aber nun mal in einer Baum-Struktur abgelegt. Um das vernünftig aufbrechen zu können packt man den Dateiinhalt in so einen Baum und kann sich dann aus diesem Baum einfach bedienen.

Der Baum ist nur für das Einlesen gedacht. Kann aber, wenn der Baum durch die Daten befüllt wird auch dazu dienen wieder eine GEDCOM-Datei zu erstellen.

Das muss man ganz klar trennen.

Beispiel der Knoten NOTE kann Unterknoten CONT und der Unterknoten CONC haben. Da alle zugehörigen aber an NOTE hängen, kann ich aus dem Knoten NOTE den gesamten Text auslesen und in ein Memo-Feld einer Datenbank speichern.

hansklok 11. Dez 2014 18:58

AW: Gedcom-Datei parsen
 
OK, soweit habe ich das verstanden.

Ich lese die Datei via TextInputStream ein (in Delphi TStringList) - und zwar Zeilenweise. Ich überprüfe, ob die Zeile mit 0 beginnt und extrahiere dann den Typ. Soweit klappt das.
Wenn Das Objekt vom z.B. Typ "INDI" ist, Erstelle ich dementsprechend eine neues IndividualRecord und rufe dessen Parser-Methode auf. Auch das klappt. ABER, und jetzt wieder zum Algorithmus, wie kann ich die Folgezeilen auslesen, ohne, dass ich unendlich viele und unnötige Schleifen aufmache?

Sir Rufo 11. Dez 2014 22:35

AW: Gedcom-Datei parsen
 
Also das hier lädt mir eine komplette StressTest-Demo-Datei ein
Delphi-Quellcode:
procedure TGedFile.LoadFromFile( const Filename: string );
var
  LValue: TDataRecord;
  LCurrent: TNode;
  LCurrentIdx: Integer;
  LLines: TStringList;
  LLine: string;
begin
  LCurrent := Self;
  LCurrentIdx := 0;

  LLines := TStringList.Create;
  try

    LLines.LoadFromFile( Filename );

    for LLine in LLines do
      begin

        LValue := ParseLine( LLine );

        while LCurrentIdx <> LValue.Level do
          begin
            if LCurrentIdx < LValue.Level
            then
              begin
                LCurrent := LCurrent.LastChild;
                Inc( LCurrentIdx );
              end
            else
              begin
                LCurrent := LCurrent.Parent;
                Dec( LCurrentIdx );
              end;
          end;

        if LValue.DataIsReference
        then
          LCurrent := TRefNode.Create( LCurrent, TNodeType.Create( LValue.NodeTypeStr ), LValue.Data, FReferenceDict )
        else
          LCurrent := TDataNode.Create( LCurrent, TNodeType.Create( LValue.NodeTypeStr ), LValue.Data );

        Inc( LCurrentIdx );

        if not LValue.Reference.IsEmpty
        then
          FReferenceDict.Add( LValue.Reference, LCurrent );
      end;

  finally
    LLines.Free;
  end;

end;

function TGedFile.ParseLine( const ALine: string ): TDataRecord;
var
  LValues: TArray<string>;
  LPrefix: string;
begin
  LValues := ALine.Split( [' '], 3 );
  Result.Level := LValues[0].ToInteger;

  // Reference gefunden?
  if LValues[1].StartsWith( '@' )
  then
    begin
      Result.Reference := LValues[1];
      Result.NodeTypeStr := LValues[2];
    end
  else
    begin
      Result.Reference := '';
      Result.NodeTypeStr := LValues[1];
      SetLength( LValues, 2 );
    end;

  LPrefix := string.Join( ' ', LValues );

  Result.Data := ALine.Substring( LPrefix.Length + 1 );
  Result.DataIsReference := Result.Data.StartsWith( '@' );
end;
Damit habe ich die im Speicher und kann auf jeden Knoten ganz gemütlich zugreifen um die Daten nun auszulesen und sonstwie zu verarbeiten. Die erzeugten Nodes parsen hier gar nichts ... wozu auch :)

hansklok 11. Dez 2014 23:04

AW: Gedcom-Datei parsen
 
Zitat:

Zitat von Sir Rufo (Beitrag 1283151)
Also das hier lädt mir eine komplette StressTest-Demo-Datei ein

Kannst Du den Quellcode bitte bisschen kommentieren? Was ist bei Dir TDataRecord?

Was macht LValue.DataIsReference?

hansklok 11. Dez 2014 23:52

AW: Gedcom-Datei parsen
 
Zitat:

Zitat von Sir Rufo (Beitrag 1283151)
Also das hier lädt mir eine komplette StressTest-Demo-Datei ein

Kannst Du bitte deinen gesamten Source posten, dann kann ich ersten besser nachvollziehen und zweitens versuchen in Xoxo zu übersetzen, an sich nicht schwer.

Sir Rufo 12. Dez 2014 00:07

AW: Gedcom-Datei parsen
 
Zitat:

Zitat von hansklok (Beitrag 1283154)
Zitat:

Zitat von Sir Rufo (Beitrag 1283151)
Also das hier lädt mir eine komplette StressTest-Demo-Datei ein

Kannst Du den Quellcode bitte bisschen kommentieren? Was ist bei Dir TDataRecord?

Was macht LValue.DataIsReference?

Eigentlich habe ich doch recht sprechenden Quelltext:
Delphi-Quellcode:
// Wenn der Data-String mit einem @ startet, dann ist es eine Referenz
Result.DataIsReference := Result.Data.StartsWith( '@' );
Wenn man sich die Sätze anschaut, dann sind die alle nach dem gleichen Muster gestrickt
Code:
<LEVEL>[<sep>@<REFERENCE>@]<sep><TYPE>[<sep><DATA>]

<LEVEL> = numerisch
<sep> = SPACE
<TYPE> = alphanumerisch ohne <sep>
<DATA> = alles bis zum Ende der Zeile
Das war es schon.

In den Record
Delphi-Quellcode:
TDataRecord
fülle ich einfach die Werte aus der Zeile ein.

Hier der gesamte Code:
Delphi-Quellcode:
program dp_183093;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.Generics.Collections,
  System.IOUtils,
  System.Classes,
  System.SysUtils;

type
  TDataRecord = record
    Level: Integer;
    Reference: string;
    NodeTypeStr: string;
    Data: string;
    DataIsReference: Boolean;
  end;

  TNodeType = record
  private
    FTypeName: string;

  public
    constructor Create( const ATypeName: string );
    function ToString: string;
    property TypeName: string read FTypeName;
  end;

  TNode = class
  private
    FNodeType: TNodeType;
    FParent: TNode;
  protected
    function GetData: string; virtual;
    function GetLastChild: TNode; virtual; abstract;
    function GetChildCount: Integer; virtual; abstract;
    function GetChild( Index: Integer ): TNode; virtual; abstract;
  public
    constructor Create( AParent: TNode; ANodeType: TNodeType );

    procedure AddChild( ANode: TNode ); virtual; abstract;
    function ToString: string; override;

    property Data: string read GetData;
    property ChildCount: Integer read GetChildCount;
    property Children[Index: Integer]: TNode read GetChild;

    property Parent: TNode read FParent;
    property LastChild: TNode read GetLastChild;
  end;

  TParentNode = class( TNode )
  private
    FChildren: TList<TNode>;
  protected
    function GetLastChild: TNode; override;
    function GetChildCount: Integer; override;
    function GetChild( Index: Integer ): TNode; override;
  public
    constructor Create( AParent: TNode; ANodeType: TNodeType );
    destructor Destroy; override;

    procedure AddChild( ANode: TNode ); override;
  end;

  TRefNode = class( TParentNode )
  private
    FDataReference: string;
    FReferenceDict: TDictionary<string, TNode>;
  protected
    function GetChildCount: Integer; override;
    function GetChild( Index: Integer ): TNode; override;
    function GetData: string; override;
  public
    constructor Create( AParent: TNode; ANodeType: TNodeType; const ADataReference: string; AReferenceDict: TDictionary<string, TNode> );
  end;

  TDataNode = class( TParentNode )
  private
    FData: string;
  protected
    function GetData: string; override;
  public
    constructor Create( AParent: TNode; ANodeType: TNodeType; const AData: string );

  end;

  TGedFile = class( TParentNode )
  private
    FReferenceDict: TDictionary<string, TNode>;
    function GetParent( Index: Integer ): TNode;
    function ParseLine( const ALine: string ): TDataRecord;
  public
    constructor Create( );
    destructor Destroy; override;

    procedure LoadFromFile( const Filename: string );
  end;

  { TNode }

constructor TNode.Create( AParent: TNode; ANodeType: TNodeType );
begin
  inherited Create;
  FNodeType := ANodeType;
  if Assigned( AParent )
  then
    AParent.AddChild( Self );
end;

function TNode.GetData: string;
begin
  Result := '';
end;

function TNode.ToString: string;
begin
  if Data.IsEmpty
  then
    Result := FNodeType.ToString
  else
    Result := FNodeType.ToString + ' ' + Data.QuotedString;
end;

{ TGedFile }

constructor TGedFile.Create( );
begin
  inherited Create( nil, TNodeType.Create( 'FILE' ) );
  FReferenceDict := TDictionary<string, TNode>.Create;
end;

destructor TGedFile.Destroy;
begin
  FReferenceDict.Free;
  inherited;
end;

function TGedFile.GetParent( Index: Integer ): TNode;
begin
  Result := Self;
  while Index > 0 do
    begin
      if not Assigned( Result )
      then
        raise Exception.Create( 'Fehlermeldung' );
      Result := Result.LastChild;
      Dec( Index );
    end;
end;

procedure TGedFile.LoadFromFile( const Filename: string );
var
  LValue: TDataRecord;
  LCurrent: TNode;
  LCurrentIdx: Integer;
  LLines: TStringList;
  LLine: string;
begin
  LCurrent := Self;
  LCurrentIdx := 0;

  LLines := TStringList.Create;
  try

    LLines.LoadFromFile( Filename );

    for LLine in LLines do
      begin

        LValue := ParseLine( LLine );

        while LCurrentIdx <> LValue.Level do
          begin
            if LCurrentIdx < LValue.Level
            then
              begin
                LCurrent := LCurrent.LastChild;
                Inc( LCurrentIdx );
              end
            else
              begin
                LCurrent := LCurrent.Parent;
                Dec( LCurrentIdx );
              end;
          end;

        if LValue.DataIsReference
        then
          LCurrent := TRefNode.Create( LCurrent, TNodeType.Create( LValue.NodeTypeStr ), LValue.Data, FReferenceDict )
        else
          LCurrent := TDataNode.Create( LCurrent, TNodeType.Create( LValue.NodeTypeStr ), LValue.Data );

        Inc( LCurrentIdx );

        if not LValue.Reference.IsEmpty
        then
          FReferenceDict.Add( LValue.Reference, LCurrent );
      end;

  finally
    LLines.Free;
  end;

end;

function TGedFile.ParseLine( const ALine: string ): TDataRecord;
var
  LValues: TArray<string>;
  LPrefix: string;
begin
  LValues := ALine.Split( [' '], 3 );
  Result.Level := LValues[0].ToInteger;

  // Reference gefunden?
  if LValues[1].StartsWith( '@' )
  then
    begin
      Result.Reference := LValues[1];
      Result.NodeTypeStr := LValues[2];
    end
  else
    begin
      Result.Reference := '';
      Result.NodeTypeStr := LValues[1];
      SetLength( LValues, 2 );
    end;

  LPrefix := string.Join( ' ', LValues );

  Result.Data := ALine.Substring( LPrefix.Length + 1 );
  Result.DataIsReference := Result.Data.StartsWith( '@' );
end;

{ TNodeType }

constructor TNodeType.Create( const ATypeName: string );
begin
  FTypeName := ATypeName.ToUpper;
end;

function TNodeType.ToString: string;
begin
  Result := FTypeName;
end;

{ TParentNode }

procedure TParentNode.AddChild( ANode: TNode );
begin
  inherited;
  if Assigned( ANode.Parent ) and ( ANode.Parent <> nil )
  then
    raise Exception.Create( 'Fehlermeldung' );

  ANode.FParent := Self;

  if not FChildren.Contains( ANode )
  then
    FChildren.Add( ANode );
end;

constructor TParentNode.Create( AParent: TNode; ANodeType: TNodeType );
begin
  inherited Create( AParent, ANodeType );
  FChildren := TObjectList<TNode>.Create( );
end;

destructor TParentNode.Destroy;
begin
  FChildren.Free;
  inherited;
end;

function TParentNode.GetChild( Index: Integer ): TNode;
begin
  Result := FChildren[Index];
end;

function TParentNode.GetChildCount: Integer;
begin
  Result := FChildren.Count;
end;

function TParentNode.GetLastChild: TNode;
begin
  Result := FChildren.Last;
end;

{ TRefNode }

constructor TRefNode.Create( AParent: TNode; ANodeType: TNodeType; const ADataReference: string; AReferenceDict: TDictionary<string, TNode> );
begin
  inherited Create( AParent, ANodeType );
  FDataReference := ADataReference;
  FReferenceDict := AReferenceDict;
end;

function TRefNode.GetChild( Index: Integer ): TNode;
var
  LRefNode: TNode;
begin
  LRefNode := FReferenceDict[FDataReference];

  if index < LRefNode.ChildCount
  then
    Result := LRefNode.Children[Index]
  else
    Result := inherited GetChild( Index - LRefNode.ChildCount );
end;

function TRefNode.GetChildCount: Integer;
begin
  Result := inherited GetChildCount + FReferenceDict[FDataReference].ChildCount;;
end;

function TRefNode.GetData: string;
begin
  Result := FDataReference;
end;

{ TDataNode }

constructor TDataNode.Create( AParent: TNode; ANodeType: TNodeType; const AData: string );
begin
  inherited Create( AParent, ANodeType );
  FData := AData;
end;

function TDataNode.GetData: string;
begin
  Result := FData;
end;

function OutputNode( ANode: TNode; ALevel: Integer = 0; AFollowRef: Boolean = True ): string;
var
  LIdx: Integer;
  LSB: TStringBuilder;
begin
  LSB := nil;
  try

    LSB := TStringBuilder.Create;
    LSB.Append( ' ', ALevel );
    LSB.Append( ANode.ToString );
    if ( ANode is TRefNode )
    then
      begin
        LSB.Append( ' (Ref)' );
      end;

    if ( ANode is TRefNode ) and not AFollowRef
    then
      begin
        LSB.Append( ' [NOT FOLLOWED]' );
        LSB.AppendLine;
      end
    else
      begin

        LSB.AppendLine;

        for LIdx := 0 to ANode.ChildCount - 1 do
          LSB.Append(
            {} OutputNode(
              {} ANode.Children[LIdx],
              {} ALevel + 1,
              {} not( ANode is TRefNode )
              {} ) );

      end;

    Result := LSB.ToString;
  finally
    LSB.Free;
  end;
end;

procedure Main;
var
  LFile: TGedFile;
  LFilename: string;
begin
  LFile := TGedFile.Create( );
  try

    LFilename := '..\..\TestGED.ged';

    LFile.LoadFromFile( LFilename );
    TFile.WriteAllText( TPath.ChangeExtension( LFilename, '.txt' ), OutputNode( LFile ) );
  finally
    LFile.Free;
  end;
end;

begin
  try
    Main;
  except
    on E: Exception do
      WriteLn( E.ClassName, ': ', E.Message );
  end;
  ReadLn;

end.

Jumpy 12. Dez 2014 09:02

AW: Gedcom-Datei parsen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Aus der verlinkten Spezi:

Zitat:

Eine GEDCOM Übertragung beinhaltet eine Datenbank in Form eines sequenziellen Datenstromes aus
mit einander verbundenenDatensätzen. Ein Datensatz wird durch eine Abfolge von gekennzeichneten
Zeilen variabler Länge repräsentiert, die in einer Hierarchie angeordnet sind. Eine Zeile besteht immer aus der Nummer einer Hierarchieebene, einem Kennzeichen (Tag) und optional einem Wert. Eine Zeile kann außerdem eine Querverweis-ID oder Querverweiszeiger beinhalten.
[...]
Eine Reihe von einer oder mehr Zeilen erzeugt einen Datensatz. Der Anfang eines neuen
Datensatzes wird durch eine Zeile gekennzeichnet, die mit der Ebenennummer 0 (Null) beginnt.
Nur weil es um Stammbäume geht und der Inhalt der Datei aussieht wie eine Baumstruktur, erhöht es mMn nur die Komplexität, das beim einlesen unbedingt in eine Baumstruktur zu schaufeln, da in dem Baum dann Äpfel, Birnen und Nüsse hängen (Familien, Personen, Beziehungen, Sourcen, ...) die anschließend extra wieder gepflückt und auf ihre Körbe verteilt werden müssen. Da kann ich die doch direkt so wie die von der Palette/der gemischten Kiste (der Datei) kommen auf die Körbe verteilen.

Es werden doch einfach nur Datensätze(!) geschickt die u.U. miteinander verknüpft sind (über die Querverweis ID) und deren Inhalte/Daten hierarchisch angeordnet sind. Sprich, wenn dann haben die einzelenen Datensätze eine Baumstruktur aber nicht unbedingt die Datei (Hat der LKW eine Baumstruktur?).

Irgendwann müssen doch die konkreten Objekte für die Geschäftslogik erzeugt werden, was ist da der Vorteil der Baumstruktur bzw. das ich mir vorher die Mühe mache "abstrakte" (im Sinne von unkonkrete) Objekte in Baumstruktur zu erzeugen? Das der Zugriff einfacher ist?

Sir Rufo 12. Dez 2014 09:10

AW: Gedcom-Datei parsen
 
@Jumpy

Der Inhalt der Datei ist wie ein Baum aufgebaut. Ich überführe nur den Inhalt 1:1 in eine entsprechend auswertebare Struktur.
Mehr mache ich nicht.

Ausserdem muss man im Zweifelsfall erst die gesamte Datei ausgelesen haben, um auf die Referenzen auch zugreifen zu können.

Hier ein Auszug aus https://code.google.com/p/geddiff/so...ples/royal.ged und zeigt einen kompletten Einzel-Satz (Zeile 41)
Code:
0 @I1@ INDI
1 NAME Victoria /Hanover/
1 TITL Queen of England
1 SEX F
1 BIRT
2 DATE 24 MAY 1819
2 PLAC Kensington,Palace,London,England
1 DEAT
2 DATE 22 JAN 1901
2 PLAC Osborne House,Isle of Wight,England
1 BURI
2 PLAC Royal Mausoleum,Frogmore,Berkshire,England
1 REFN 1
1 FAMS @F1@
1 FAMC @F42@
Wie bitteschön, soll denn jetzt die Referenz zu @F1@ und @F42@ behandelt werden? Die kommen in der Datei erst ein paar Zeilen später ...

Ab Zeile 23285 kommt
Code:
0 @F1@ FAM
1 HUSB @I2@
1 WIFE @I1@
1 CHIL @I3@
1 CHIL @I4@
1 CHIL @I5@
1 CHIL @I6@
1 CHIL @I7@
1 CHIL @I8@
1 CHIL @I9@
1 CHIL @I10@
1 CHIL @I11@
1 DIV N
1 MARR
2 DATE 10 FEB 1840
2 PLAC Chapel Royal,St. James Palace,England

Jumpy 12. Dez 2014 09:31

AW: Gedcom-Datei parsen
 
Ich verstehe glaub ich wie du das meinst. Aber wenn du jetzt anfängst die Objekte der Geschäftslogik zu erstellen (also der nächste Schritt) machst du das ja dann in dem du dem Baum Schritt für Schritt abgehst. Hast du dann nicht das selbe Problem, wenn du an die Stelle kommst, dass die "konkreten" Objekte auf die verweisen wird noch nicht existieren weil die "abstrakte" Objekte mit der Info darüber im Baum noch ein paar Zweige tiefer hängen?

OK, du wirst sie leichter finden und nach Bedarf erzeugen können.


Wobei ich gerade überlege (ich hab allerdings keine Ahnung von Genealogie-Programmen) dass es eh nicht möglich(?)/einfach ist diese Objekte OOP-mäßig miteinander zu verknüpfen (assoziieren?). Hätte jetzt gedacht, dass die Objekte sortenrein in entsprechenden Collections liegen und in anderen Objekten gerade mal die Referenz-ID auf diese gespeichert wird und man dann die Collection fragen muss: Gib mir mal die Familie mir der ID F12, oder so. (Zumindest die Objekte auf Ebene 0).
Objekte auf höheren Ebenen würden wahrscheinlich mit dem übergeordneten Objekt erzeugt und im übergeordneten Objekt "verwaltet". Referenziert würden die glaub ich ala @I12!P2@ oder so, hab da aber bisher kein konkretes Beispiel für gesehen nur die Spezi so verstanden, das es das geben könnte.

Sir Rufo 12. Dez 2014 10:02

AW: Gedcom-Datei parsen
 
@Jumpy

Nein habe ich nicht, denn dafür wird bei einem Referenz-Verweis auch ein
Delphi-Quellcode:
TRefNode
erstellt mit direktem Zugriff auf die referenzierte Node (müsste noch leicht verfeinert werden).

Auf jeden Fall kann man gleich prüfen, ob man diese Referenz schon gespeichert hat, wenn nicht speichert man die.

Sir Rufo 12. Dez 2014 10:21

AW: Gedcom-Datei parsen
 
Ich glaube ich habe bei der Beschreibung des Zeilenaufbaus einen kleinen Fehler gemacht.

So ist die korrekte Logik für die Zeile
Code:
<LEVEL> -- <SEP> -+- <TYPE> -- <SEP> -+- <DATA> ---+- <EOL>
                  |                   +- <REFTO> --+
                  +- <REF> -- <SEP> -- <TYPE> ------- <EOL>
Wenn die Zeile also eine Referenz ist
Code:
0 @foo@ INDI
dann folgen keine Daten mehr.

Wenn die Zeile auf eine Referenz verweist, dann beinhalten die Daten die Referenz
Code:
0 INDI @foo@
Das müsste also alles falsch sein
Code:
0 @foo@ INDI @foo@
0 @foo@ INDI Some data
0 INDI @foo@ and some data

Jumpy 12. Dez 2014 11:15

AW: Gedcom-Datei parsen
 
Zitat:

Zitat von Sir Rufo (Beitrag 1283209)
@Jumpy
Nein habe ich nicht, denn dafür wird bei einem Referenz-Verweis auch ein
Delphi-Quellcode:
TRefNode
erstellt mit direktem Zugriff auf die referenzierte Node (müsste noch leicht verfeinert werden).

Auf jeden Fall kann man gleich prüfen, ob man diese Referenz schon gespeichert hat, wenn nicht speichert man die.

Na gut, das Problem ist schon da, aber du löst es bereits bevor es zum Problem wird.

Das kommt ja letztlich daher, dass die Datensätze in beliebiger Reihenfolge in der Datei stehen können und daher dass zirkuläre Referenzen erlaubt sind, d.h. es wäre gar nicht möglich die Daten so zu speichern, dass man daraus die Objekte in einer Reihenfolge erzeugt die bewirkt, das Referenzierte Objekte bereits zuvor erstellt werden.

----------

Kann das sein das
Code:
0 INDI @foo@
auch falsch ist?

Code:
1 INDI @foo@
aber OK?

Muss der Eintrag auf Ebene 0 nicht eine Ref sein, entspricht doch quasi einem Primary Key, den jeder Datensatz braucht?

Sir Rufo 12. Dez 2014 13:32

AW: Gedcom-Datei parsen
 
Code:
0 INDI @foo@
Ist nicht falsch, aber in dem Kontext unsinnig.
Code:
0 NOTE @foo@
macht schon mehr Sinn

hansklok 12. Dez 2014 14:12

AW: Gedcom-Datei parsen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Sir Rufo (Beitrag 1283191)
Ausserdem muss man im Zweifelsfall erst die gesamte Datei ausgelesen haben, um auf die Referenzen auch zugreifen zu können.

Da hat Sir Rufo recht!
Zitat:

Zitat von Jumpy (Beitrag 1283199)
Wobei ich gerade überlege (ich hab allerdings keine Ahnung von Genealogie-Programmen) dass es eh nicht möglich(?)/einfach ist diese Objekte OOP-mäßig miteinander zu verknüpfen (assoziieren?). Hätte jetzt gedacht, dass die Objekte sortenrein in entsprechenden Collections liegen und in anderen Objekten gerade mal die Referenz-ID auf diese gespeichert wird und man dann die Collection fragen muss: Gib mir mal die Familie mir der ID F12, oder so. (Zumindest die Objekte auf Ebene 0).
Objekte auf höheren Ebenen würden wahrscheinlich mit dem übergeordneten Objekt erzeugt und im übergeordneten Objekt "verwaltet". Referenziert würden die glaub ich ala @I12!P2@ oder so, hab da aber bisher kein konkretes Beispiel für gesehen nur die Spezi so verstanden, das es das geben könnte.

Genauso ist es. Es werden nur die Verweiszeiger, also die ReferenceIDs gespeichert. Alle Hauptobjekte werden in Collections verwaltet (INDI, FAM, SOUR, OBJ, NOTE).
Zitat:

Zitat von Sir Rufo (Beitrag 1283262)
Code:
0 INDI @foo@
Ist nicht falsch, aber in dem Kontext unsinnig.
Code:
0 NOTE @foo@
macht schon mehr Sinn

Sir Rufo, da hast Du wiederum recht, allerdings schreibt der Standard explizit folgende Notation für Hauptobjekte außer HEAD und TRLR vor:

0 @I123@ INDI
0 @F123@ FAM
0 @N123@ NOTE
0 @S123@ SOUR
0 @O123@ OBJ

Header und Trailer (kommen einmalig pro Datei vor!):
0 HEAD
0 TRLR

Ich hänge mal den übersetzten Xojo-Code (Basic) ran. Allerdings kommt es zu Exceptions (habe das kommentiert). Auch, was nicht geht. Vielleicht findet Ihr den Fehler.
Achso: Xoxo kennt keine StringBuilder-Klasse. ich habe jetzt einfach einen String definiert und ihm immer wieder die neuen Teile angehängt. Das ist doch dasselbe, oder? Siehe OutputNode().

Danke für diesen angeregten, spannenden Thread.

Jumpy 12. Dez 2014 14:40

AW: Gedcom-Datei parsen
 
Das fehlende List.Contains(ANode) musst du wohl selber nachbauen, wenn die Collection das nicht kann. Im einfachsten Fall einfach eine Prozedur, der man Collection und Element übergibt und die dann durch alle Elemente iteriert und schaut, ob es das Element schon gibt.

Oder aber Dictionary statt Collection nehmen, vllt. kann das mehr?

Sir Rufo 12. Dez 2014 15:10

AW: Gedcom-Datei parsen
 
Ja, der StringBuilder ist nur schneller und rührt nicht so im Speicher herum.
Delphi-Quellcode:
LStr := '';
for LIdx := 1 to 1000 do
  LStr := LStr + 'a';
Result := LStr;
ist analog zu
Delphi-Quellcode:
LSB := TStringBuilder.Create();
try
  for LIdx := 1 to 1000 do
    LSB.Append( 'a' );
  Result := LSB.ToString;
finally
  LSB.Free;
end;

hansklok 13. Dez 2014 00:18

AW: Gedcom-Datei parsen
 
...ach verdammt, ich kriege es nicht zum laufen.

Was wäre denn noch ein Konzept so eine Datei, ressourcenschonend, einzulesen?

ktweigel 16. Okt 2016 16:56

AW: Gedcom-Datei parsen
 
Hallo,
ist zwar schon eine Weile her, dass die Frage diskutiert wurde, aber ich doktere seit Jahren an demselben Problem herum.

Eigentlich will ich lediglich ein möglichst reines GEDCOM (Version 5.5.1) schreiben und benutze dazu das Programm AGES 2.0 (http://www.daubnet.com/ages), weil es die Daten sofort in diesem Format speichert und einliest. Dabei sind die Unterschiede zum 'reinen' GEDCOM durch anschließende Bearbeitung leicht zu entfernen (z.Bsp. das von AGES benutzte Feld _UID). Anschließend möchte ich die textlichen Teile in einem listenartigen Ausdruck mittels LaTeX ausdrucken. AGES lässt einem zwar in der Reportgestaltung ziemlich freie Hand, hat aber leider nicht an allen Stellen alle notwendigen Felder zur Verfügung. Insbesondere der Hinweis auf die Quellennummer, die ich gern in einer Hochzahl hinter dem jeweiligen Eintrag hätte, ist nicht möglich.

Vor Jahren habe ich mich einmal mit dem GEDCOM-Parser für Delphi 'My Family Tree' (https://sourceforge.net/projects/myf...urce=directory - testproj-win32-0.1.1.zip) auseinandergesetzt, bin aber nicht bis zum Letzten durchgestiegen.

Ein weiteres Programm, das LaTeX-Ausdrucke von GEDCOM-Dateien vorsieht, ist LifeLines, das aber seit Jahren nicht weiterentwickelt wird.

Meine Frage an hansklok ist nun, ob er mit seinem Problem weitergekommen ist und mich eventuell an seinen Fortschritten teilhaben lässt, oder ob ich mich in das oldie LifeLines einarbeiten soll.

Gruß ktweigel (Thomas)

hansklok 17. Okt 2016 16:26

AW: Gedcom-Datei parsen
 
Zitat:

Zitat von ktweigel (Beitrag 1351039)
Meine Frage an hansklok ist nun, ob er mit seinem Problem weitergekommen ist und mich eventuell an seinen Fortschritten teilhaben lässt, oder ob ich mich in das oldie LifeLines einarbeiten soll.

Lieber Thomas,
ja, ich bin noch an der Sache dran. Nur dauert meine Arbeit noch an, da wir es mit einer sehr komplexen Struktur zu tun haben und alle möglichen genealogischen Zusammensetzungen (Cousin/en-Ehe, Inzucht etc.) berücksichtigt werden müssen. Das ist alles, was ich bisher dazu sagen kann. Ich halte an dieser Stelle aber auf dem Laufenden. Bei genaueren Fragen, Anregungen und Wünschen, gerne eine persönliche Nachricht hier schreiben.

Gruß hansklok

ktweigel 17. Okt 2016 19:32

AW: Gedcom-Datei parsen
 
Zitat:

Zitat von hansklok (Beitrag 1351116)
Zitat:

Zitat von ktweigel (Beitrag 1351039)
Meine Frage an hansklok ist nun, ob er mit seinem Problem weitergekommen ist und mich eventuell an seinen Fortschritten teilhaben lässt, oder ob ich mich in das oldie LifeLines einarbeiten soll.

Lieber Thomas,
ja, ich bin noch an der Sache dran. Nur dauert meine Arbeit noch an, da wir es mit einer sehr komplexen Struktur zu tun haben und alle möglichen genealogischen Zusammensetzungen (Cousin/en-Ehe, Inzucht etc.) berücksichtigt werden müssen. Das ist alles, was ich bisher dazu sagen kann. Ich halte an dieser Stelle aber auf dem Laufenden. Bei genaueren Fragen, Anregungen und Wünschen, gerne eine persönliche Nachricht hier schreiben.

Gruß hansklok

Lieber hansklok,
das mit den komplexen Strukturen kann ich nur bestätigen. Ich habe mich deshalb auch bisher davor gescheut, die Daten in einer Datenbank zu halten. Aber wenn man GEDCOM benutzt wird man dafür mit x. rekursiven Strukturen 'belohnt'. Bin nur Hobbyprogrammierer. Werde mir jetzt noch mal das Programm 'Ancestromania' anschauen (http://www.liberlog.fr/spip.php?page...&id_article=30), ob ich es aus den Quellen zum Laufen bekommen und ob ich dann eventuell an den Berichten etwas herumschrauben kann. Eine tex-Datei aus Lazarus heraus (mein Delphi geht auf Windows 8.1 nicht mehr) habe ich immerhin schon hinbekommen.

Am liebsten wäre es mir allerdings, man bekäme den Quellcode von AGES, das ja in DELPHI geschrieben wurde und könnte, falls man ihn versteht, die eigenen Bedürfnisse einprogrammieren.


Gruß Thomas (ktweigel)

ktweigel 6. Apr 2018 10:14

AW: Gedcom-Datei parsen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo hansklok,

Dieser Tread schweigt nun schon seit etlichen Jahren. Bist Du denn mit den komplexen Strukturen weitergekommen. Inzwischen hat ein Prof. Sturm eine LATEX-Package namens 'genealogytree.sty' entwickelt, die höchst qualitätvolle Stammbäume ausdrucken kann (Anhang 48759). Leider gibt es keine Anbindung an das GEDCOM-Format. Und jede einzelne Person in die LATEX-Datei eintragen ist keine Option.

Gruß Thomas

hansklok 7. Apr 2018 11:22

AW: Gedcom-Datei parsen
 
Hallo Thomas, habe via Persönlicher Nachricht geantwortet!


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:24 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz