![]() |
Re: himXML (gesprochen himix ML)
OK, waren zwar mehr, als nur ein paar Minuten,
aber was sind schon fast genau 2277 Minütchen :angel2: Nja, zumindestens kompiliert es wieder unter D2006 (TDE) und vermutlich auch unter D2007 (welches ich nicht zur Hand hab). |
Re: himXML (gesprochen himix ML)
Zitat:
// Edit: Ja, es kompiliert mit Delphi2007 :-) Gruß Patrick |
Re: himXML (gesprochen himix ML)
Zitat:
ja und in Delphi 2010 läuft es nun ebenfalls Außerdem hab ich die entsprechenden Stellen so angepaßt, daß ich nun z.B. die Größenangabe eines Arrays vornehm, anstatt Array[TTypeKind], womit es bei zukünftigen Erweiterungen der RTTI weiterhin funktioniert. Und wenn einer Erweiterung/Änderung erkannt wird, dann wird eine Compilerwarnung ausgegeben und mit nur den bekannten Typen gearbeitet, anstatt da die Compilierung abbricht. |
Re: himXML (gesprochen himix ML)
himi,
irgendwat passt da bei der TXMLIniFile nicht, oder ich bin schlicht zu doof: Wenn ich einen DateTime-Wert auslesen will, bekomme ich dit hier: Zitat:
Delphi-Quellcode:
Der Key sieht so aus:
Function TXMLIniFile.ReadDateTime(Const Section, Ident: String; Default: TDateTime): TDateTime;
Begin If ValueExists(Section, Ident) Then Try Result := _XML.RootNode.Nodes['section>name=' + Section].Nodes['ident>name=' + Ident].Text; //<= Kaboom.. :P Except Result := Default; End Else Result := Default; End;
XML-Code:
Gelesen wird so:
<section name="Overview">
<ident name="DoUseLastTimeSpan">True</ident> <ident name="FromDate">2009-06-06T12-04-43.687</ident> <ident name="ToDate">2009-10-06T12-04-43.687</ident> <ident name="DateSelection">7</ident> </section>
Delphi-Quellcode:
Geschrieben so:
fFromDate := fXMLIni.ReadDateTime('Overview', 'FromDate', Now);
fToDate := fXMLIni.ReadDateTime('Overview', 'ToDate', Now);
Delphi-Quellcode:
Und manchmal tritt dieser Fehler auf:
fXMLIni.WriteDateTime('Overview', 'FromDate', fFromDate);
fXMLIni.WriteDateTime('Overview', 'ToDate', fToDate); Zitat:
Und nu' kommst du. :stupid: |
Re: himXML (gesprochen himix ML)
Ups, kennst du das Problem, wenn man 'ne Indexzählung umstellt und sich dann verzählt? :oops:
Das Ergebnis war, daß die TDateTime-Werte nimmer von ihrer XML-Darstellung in ein passendes Format umgewandelt wurden :wall:
Delphi-Quellcode:
// diese Funktionen in der himXML.pas einfach ändern
Class Function TXHelper.isXMLDateTime(Const S: TWideString): Boolean; Var P, i, i2, i3: Integer; D: TDateTime; Begin P := 0; If (Length(S) >= P + 10) and (S[P + 5] = '-') and (S[P + 8] = '-') and TryStrToInt(Copy(S, P + 1, 4), i) and TryStrToInt(Copy(S, P + 6, 2), i2) and TryStrToInt(Copy(S, P + 9, 2), i3) and TryEncodeDate(i, i2, i3, D) Then Inc(P, 10); If (Length(S) >= P + 9) and (S[P + 1] = 'T') and (((S[P + 4] = '-') and (S[P + 7] = '-')) or ((S[P + 4] = ':') and (S[P + 7] = ':'))) and TryStrToInt(Copy(S, P + 2, 2), i) and TryStrToInt(Copy(S, P + 5, 2), i2) and TryStrToInt(Copy(S, P + 8, 2), i3) and TryEncodeTime(i, i2, i3, 0, D) Then Inc(P, 9); If (Length(S) >= P + 4) and (S[P + 1] = '.') and TryStrToInt(Copy(S, P + 2, 3), i) Then Inc(P, 4); If (Length(S) >= P + 1) and (S[P + 1] = 'Z') Then Inc(P); Result := Length(S) = P; End; Class Function TXHelper.XMLToDateTime(Const S: TWideString): TDateTime; Var P, i, i2, i3: Integer; D: TDateTime; Begin Result := 0; P := 0; If (Length(S) >= P + 10) and (S[P + 5] = '-') and (S[P + 8] = '-') and TryStrToInt(Copy(S, P + 1, 4), i) and TryStrToInt(Copy(S, P + 6, 2), i2) and TryStrToInt(Copy(S, P + 9, 2), i3) and TryEncodeDate(i, i2, i3, D) Then Begin Inc(P, 10); Result := D; End; If (Length(S) >= P + 9) and (S[P + 1] = 'T') and (((S[P + 4] = '-') and (S[P + 7] = '-')) or ((S[P + 4] = ':') and (S[P + 7] = ':'))) and TryStrToInt(Copy(S, P + 2, 2), i) and TryStrToInt(Copy(S, P + 5, 2), i2) and TryStrToInt(Copy(S, P + 8, 2), i3) and TryEncodeTime(i, i2, i3, 0, D) Then Begin Inc(P, 9); Result := Result + D; End; If (Length(S) >= P + 4) and (S[P + 1] = '.') and TryStrToInt(Copy(S, P + 2, 3), i) Then Begin Inc(P, 4); Result := Result + (i / (24*60*60*1000)); End; If (Length(S) >= P + 1) and (S[P + 1] = 'Z') Then Inc(P); If Length(S) <> P Then Raise EXMLException.Create(Self, 'XMLToDateTime', @SCorupptedDateTime, Copy(S, P + 1, 20)); End; Was das Andere betrifft ... das ist erstmal ein Fehler im FileStream, welcher meckert, daß da eine Datei nicht geöffnet werden konnte. Problem dabei ist, daß die TWideFileStream-Klasse nur eine "Kopie" von TFileStream ist und ich da bis auf das Unicode nichts geändert hab ... erstmal möchte ich an diesem Stream natürlich nichts ändern und es würde auch nichts bringen, wenn ich da versuche etwas zu ändern. :angel2: Aber so wie es aussieht, ist diese Datei wohl schon geöffnet und ja ... keine Ahnung was Windows da genau will. [google]"Der Vorgang ist bei einer Datei mit einem geöffneten Bereich, der einem Benutzer zugeordnet ist, nicht anwendbar"[/google] |
Re: himXML (gesprochen himix ML)
Zitat:
Und mit der zweiten Meldung... Hmm... :gruebel: |
Re: himXML (gesprochen himix ML)
Wie gesagt, dein 2. Problem kann ich so erstmal nicht beheben ... dafür müßte man erstmal rausbekommen, wer oder was die Datei zu diesem Zeitpunkt noch geöffnet hält und müßte dieses dann beheben.
So, die kleinen Änderungen aus Post #165 sind in den beta-Download mit eingeflossen. Und dann wurde ein böser Fehler in der Kodierung entdeckt, welcher beim Einlesen sozusagen das Encoding, welches im BOM angegeben ist einfach ignorierte/überschrieb. > ![]() Nun noch etwas zu Razor's Problemchen: > UTF-16 wird halt nicht unterstützt Wenn nun nichts UTF-16-Spezifisches vorhanden hist, dann könnte man entweder einfach das Encoding-Attribut gegen Unicode (ISO-10646-UCS-2) austauschen
XML-Code:
oder dieses, mit ein paar kleinen Änderungen, einfach als Unicode parsen lassen :angel2:
<?xml version="1.0" encoding="ISO-10646-UCS-2" ?>
Delphi-Quellcode:
! Zeilenangaben entsprechen der Version v0.98 beta von heute (07.10.2009 14³°)
{Zeile 584}
{alt} TXMLEncoding = (xeUTF7, xeUTF8, {xeUTF16,} xeUnicode, xeUnicodeBE, ... {neu} TXMLEncoding = (xeUTF7, xeUTF8, xeUTF16, xeUnicode, xeUnicodeBE, ... {Zeile 1515} {alt} //({xeUTF16} Encoding: 'UTF-16'; CodePage: 1200; CharSize: 2), {neu} ({xeUTF16} Encoding: 'UTF-16'; CodePage: 1200; CharSize: 2), {Zeile 8431} {alt} xeUnicode, xeUnicodeBE: {neu} xeUnicode, xeUnicodeBE, xeUTF16: {Zeile 9106} {alt} xeUnicode, xeUnicodeBE: Begin {neu} xeUnicode, xeUnicodeBE, xeUTF16: Begin |
Re: himXML (gesprochen himix ML)
Sorry to ask but does is matter whats in the header of the xml file ?
I got this but it wont work. Zitat:
|
Re: himXML (gesprochen himix ML)
Zitat:
indirekt existiert es schon lange, und theoretisch sollte es auch keine Probleme geben, da ich aber z.B. das UTF-8 nicht nach UTF-16 umwandle und ansonsten auch alles nur als normales Unicode (alles nur 16-Bit-Einzelzeichen) behandle, hatte ich es einfach nicht direkt "freigegeben". |
Re: himXML (gesprochen himix ML)
So, nachdem ich nun wieder etwas mehr Zeit habe, bin ich auch mal wieder dazu gekommen, mein XML-Projekt weiterzubasteln.
Ich habe diesbezüglich mal eine allgemeinere Frage: Was kann man nun genau alles angeben, wenn man auf einen (tieferen) Knoten zugreifen will? Folgendes konnte ich schon (durch den Thread hier) herausfinden
Delphi-Quellcode:
Irgendwo hatte ich aber auch gelesen, dass man mit
Node['tag1\tag2\tag3']; // Ineinander verschachtelte Tags
Node['tag1[2]']; // Den 3. Tag mit dem Namen tag1 im aktuellen Knoten
Delphi-Quellcode:
den tag1 auswählen können soll, der als Attribut attr den Wert value hat. Das hat bei mir aber irgendwie nicht funktioniert, oder habe ich da etwas falsch verstanden?
Node['tag1>attr=value']
Wäre nett, wenn du da eine Art Übersicht machen könntest ;) (Falls eine solche existiert, dann habe ich sie noch nicht gefunden, ein Link reicht dann ^^) MfG Zwoetzen |
Re: himXML (gesprochen himix ML)
ich bin zwar dabei eine neue Hilfe zu basteln, aber das dauert noch ein bissl
aktuell ist aber einiges in Form einer Inline-Hilfe direkt in den Dateien z.B. schau hierfür mal in die Unit himXML.pas (bzw. himXMLi.pas der alten Version) und klappe dort ganz oben die Region "Help" auf (der zweite ganz lange Kommentar) ... Delphi 2009 sollte die Regionen ja standardmäßig zugeklappt haben. dort gibt es zu einigen Dingen schon eine kleine Erklärung z.B.
Code:
// Count CountNF -
// Node NodeNF (1) - // NodeU NodeUNF (1) see .Node but node always not created, ... // NodeList NodeListNF (1) -
Code:
schwer wird es nur, da ich mein "System" versuche auszulagern, so daß es mal möglich sein sollte auch sowas wie XPath nachzurüsten, bzw. mein System durch ein Alternatives oder Userdefinierte auszutauschen.
// (1) node names allowed paths, attributes and an index
// "{\}{.\}{..\}{node...\}{nodeName}{>attr=value{>attr=value{...}}}{[index]}" // // Node['\..\node'] Owner.RootNode.Parent.Node['node'] aka ... // Node['\node'] Owner.RootNode.Node['node'] or {first ... // Node['.\node'] {Self.}Node['node'] // Node['..\node'] Parent.Node['node'] // Node['node1\node2'] Node['node1'].Node['node2'] // Node['node>attr=value'] Node['node'] with Attributes['attr']='value' // Node['node>attr=value>attr2=value2'] Node['node'] with Attributes['attr']='value' and ... // Node['node[3]'] NodeList['node'][3] // Node['[3]'] Node[3] // Node['>attr=value'] first of Node.Nodes with Attributes['attr']='value' // Node['>attr=value[3]'] 3rd of Node.Nodes with Attributes['attr']='value' // Node['*:node'] ignore namespace // Node['name:*'] first/all nodes with this namespace // // Node['node1[2]\node2>attr=value[3]'] NodeList['node1'][2].NodeList['node2'][3] with ... // // (2) attribut names allowed paths - see at (1) // "{nodePath}\attributeName" // // Attribute['node\attr'] Node['node'].Attribute['attr'] also im Grunde sollte Node['tag1>attr=value'] funktionieren. :gruebel: |
Re: himXML (gesprochen himix ML)
Danke, das hilft mir sehr weiter. Ich hatte zwar schon in die Dateien mal reingeschaut, auch die einzelnen Regions gesehen (wusste gar nicht, dass es sowas gibt :P), aber nicht wirklich etwas zu diesen Bezeichnungen gefunden. Hab vielleicht nicht genau genug gesucht ^^
Zu dem "tag1>attr=value" werd ich nochmal genauer schauen, warum das nicht funktioniert hatte. Diese "Abkürzungen" find ich übrigens sehr gut gelungen, da kommt man auch in etwas größeren Dokumenten relativ schnell an den eigentlichen Tag, den man lesen möchte :thumb: (Gerade wenn man nicht alle Informationen benötigt) |
Re: himXML (gesprochen himix ML)
Die Regionen sind schon 'ne praktische Sache, vorallem da man so auch Blöcke ausgeblendet bekommt, welche einem grade nicht "wichtig" sind und man so schneller und übersichtlicher an bestimmete Stellen kommt.
Nja, ![]() Abgesehn davon, daß hier auch schneller über Hashtabellen gesucht wird ... hab die Nodes und Attribute extra dafür optimiert. :angel: falls du Regionen auch mal selber nutzen willst...
Delphi-Quellcode:
dieses {$IF X}...{$IFEND} kannst'e ignorieren, das hab ich nur drinnen, weil ältere Delphis keine Regionen kennen
{$IF X}{$REGION 'help'}{$IFEND}
... {$IF X}{$ENDREGION}{$IFEND}
Delphi-Quellcode:
und beim Zusammenklappen wird dann nur noch der Text angezeigt ... ist praktisch das Selbe, was man mit Funktionen und Typen (Records/Klassen) machen kann, nur halt für größere Bereiche/Regionen
{$REGION 'beliebiger Text'}
... {$ENDREGION} |
Re: himXML (gesprochen himix ML)
Danke für die Antwort, wenn es sich das nächste Mal anbietet, weiß ich jetzt, wie ich etwas mehr Übersicht hineinbringen kann :mrgreen:
Ich habe jetzt auch die Zeit gefunden, das Problem mit dem Zugriff mit Attribut-Wert genauer zu untersuchen, und nun funktioniert das auch. Da muss mir wohl beim letzten Mal ein Fehler unterlaufen sein (Tippfehler oder ähnliches), dein Code funktioniert also wie er soll :wink: |
Re: himXML (gesprochen himix ML)
Hallo himitsu!
Ich versuche gerade himXML in einem anderen Projekt einzusetzen. Dabei stellt sich mir die Frage, wie komme ich an die Attribute eines Nodes.
Delphi-Quellcode:
Die Datei sieht dabei so aus:
procedure TTag.LoadFromFile(const AFilename: string);
var f : TXMLFile; begin Parent := nil; // öffnen bla bla f := TXMLFile.Create; try f.LoadFromFile(AFilename); LoadFromNode(f['virtualroot\root']); finally f.Free; end; end; procedure TTag.LoadFromNode(const AXMLNode: TXMLNode); var na : string; i, ty: Integer; t : TEntry; nds : TXMLNodeArray; begin Name := AXMLNode.Node['name'].Text; nds := AXMLNode.NodeList['files\file']; for i := 0 to High(nds) do begin ty := nds[i]['@type'].Text; // Directory Node if (ty and 1) = 1 then begin t := TTag.Create; FChilds.Add(t); t.Parent := Self; TTag(t).LoadFromNode(nds[i]); end else begin t := TEntry.Create; FFiles.Add(t); t.Name := nds[i]['name'].Text; end; t.Hidden := (ty and 2) = 2; end; end;
XML-Code:
Wenn ich nun die Zeile 28 ausführe um den Type des Nodes "taxs\virtualroot\root\files\file[0]" zu kommen.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<taxs> <virtualroot> <root> <name>Root</name> <files> <!-- Filecontainer with "filetype" Bit Meaning (if set) 1 Directory 2 Hidden --> <file type=1> <name>Sub</name> <files> <file type=3> <name>HiddenSub</name> </file> <file type=1> <name>Sub</name> <files> <file type=2> <name>HiddenFile</name> <original>C:...</original> </file> </files> </file> </files> </file> <file type=0> <name>Filetest</name> <original>C:...</original> </file> </files> </root> </virtualroot> </taxs> Zitat:
xZise |
Re: himXML (gesprochen himix ML)
Im Prinzip einfach dadurch, daß man auf die Eigenschaft .Attributes den jeweiligen Nodes zugreift :angel:
Delphi-Quellcode:
ty := nds[i].Attributes['type'];
|
Re: himXML (gesprochen himix ML)
Aha. Kann man das nicht irgendwie verkürzt schreiben?
Und jetzt habe ich ein ganz anderes komisches Problem. Und zwar wenn "LoadFromNode" gerade den "HiddenSub" Node abarbeitet, dann ist nds zwar "leer" (im Debugger steht: nds = ()), aber er geht trotzdem in die Schleife und scheitert dann grandios dabei das Attribut des ersten nicht vorhandenen Nodes auszulesen. MfG xZise |
Re: himXML (gesprochen himix ML)
Liste der Anhänge anzeigen (Anzahl: 2)
Zitat:
Zitat:
PS: was das Debuggen angeht ... In der neuen Version ist dieses in meinem Projekt standardmäßig abgeschaltet. (noch nicht hochgeladen) Und in der Beta läßt es sich über die Projektoptionen abstellen, dort einfach in den Bedingungen "hxNotDebugable" einfügen > D2009 > Projektoptionen > Delphi-Compiler > Bedingungen Dann läßt sich das eigene Programm einfacher debuggen, da nicht ständig im Einzelschritt in meine Units gewechselt wird. :angel: |
Re: himXML (gesprochen himix ML)
Liste der Anhänge anzeigen (Anzahl: 2)
Hab hier mal 'nen noch ungetesteten Code zum Speichern und Laden eines TTreeView.
Gespeichert wird natürlich der .Text und die ganzen Subnodes ... also die ganze Baum-Struktur des Trees und beim Rest kann man entschieden werden, was man speichern/laden will. Da wären die ganzen Bildindize .ImageIndex, .SelectedIndex, .StateIndex, .ExpandedImageIndex und .OverlayIndex, außerdem .Enabled und die Zustände .Selected, .Focused und .Expanded, für jeden einzelnen Node. Ein TVirtualStringTree wird auch bald folgen, dort wird .Data dann ebenso über einen Callback gespeichert und geladen.
Delphi-Quellcode:
benutzen
Type TSTVProc = Procedure(Node: TXMLNode; TVNode: TTreeNode);
TSTVSavedData = Set of (ssImageIndex, ssSelectedIndex, ssStateIndex, ssExpandedIndex, ssOverlayIndex, ssEnabled, ssSelected, ssFocused, ssExpanded, ssData); Const ssDefault = [ssImageIndex..ssSelected, ssExpanded]; Procedure SerializeTreeView(Node: TXMLNode; TreeView: TTreeView; Save: TSTVSavedData = ssDefault; DataProc: TSTVProc = nil); Procedure DeserializeTreeView(Node: TXMLNode; TreeView: TTreeView; Load: TSTVSavedData = ssDefault; DataProc: TSTVProc = nil);
Delphi-Quellcode:
Dieser und ähnliche Codes werden allerdings wohl nie direkt im Projekt enthalten sein, da sie einfach zu speziell sind,
Var XML: TXMLFile;
Node: TXMLNode; // speichern XML := TXMLFile.Create; Node := XML.AddNode('MyTreeView'); SerializeTreeView(Node, TreeView1); XML.SaveToFile('file.xml'); XML.Free; // laden XML := TXMLFile.Create; XML.LoadFromFile('file.xml'); Node := XML.Node['MyTreeView']; DeserializeTreeView(Node, TreeView1); XML.Free; aber es ist eine kleine Abteilung auf der zukünftigen Webseite vorgesehn. [edit] der ganze Code kommt gleich wieder ... dann als Anhang in 'ner eigenen Unit so, da isser wieder :) [add] nun auch getestet, etwas geändert und mit Beispiel, siehe Bild |
Re: himXML (gesprochen himix ML)
Bis auf ein paar interne Sachen wurden vorallem ein paar neue Property eingefügt.
FindNode, FindNodes, FindNodeNF und FindNodesNF sind nun in den NodeListen zu finden, sowie als Weiterleitung im RootDokument und den Nodes. Diese sind fast das Selbe wie die Property Node und NodeList, nur daß sie die gewünscheten Nodes nicht NUR direkt im gewählten Node/Dokument suchen, sondern auch in allen SubNodes. Als NodeName/Pfad kann hier die selbe Syntax verwendet werden, wie bei den normalen Nodes, wodurch man z.B. auch ganze Pfade suchen kann. XML.FindNode['MeinNode'] würde also den ersten Node mit dem Namen "MeinNode" zurückliefern, welcher irgendwo innerhalb des RootNode oder seinen SubNodes rumliegt. Für Einzelnodes (ohne Pfadangabe) wird dieses Verhalten demnächst auch in den "normalen" Node und Node-Listen verfügbar sein ... ich glaub ich werde dieses über das Präfix @ dort integrieren. |
Re: himXML (gesprochen himix ML)
Passend zu FindNode versuch ich auch mal XPath zu implementieren,
allerdings extern über 'nen Class-Helper einzubinden. (so gibt es dann auch 'ne Vorlage, falls jemand noch etwas Anderes nachrüsten will ... meine intere Pfade-Analyse abzukapseln und über eine Schnittstelle wieder einzubinden, so daß man direkt in die Klassen z.B. XPath einbinden könnte, hab ich doch gelassen ... das Ganze entsprechend umzubauen war mir dann doch zu aufwändig, wobei ich Einiges dann auch hätte ganz anders lösen müssen, falls das überhaupt ginge) als Vorlage nutze ich derzeit erstmal ![]() falls wer 'ne "nettere" Seite kennt, so melde er/sie sich bitte mal. |
Re: himXML (gesprochen himix ML)
So, hab nun genügend Infos/Links und auch die zugehörigen XPath-Specs ... ich würde mal sagen, ich überspringe die 1.0 und gehe gleich zu 2.0 .
Wer hat das eigentlich erfunden? Der gehört geteert und gefedert! Wenn man das nach Spec parsen will, dann muß man ja 'ne völlig massochistische Ader haben. :evil: Will heißen, daß ich mich erstmal vorwiegend um andere Dinge kümmer und dieses nur nebenher mal versuche hinzubekommen, womit es also noch etwas dauern kann, aber die Verschachtelungen, Befehle und sonstige Möglichkeiten sind soooooo zahlreich und etwas verwirrend ........ Dabei dachte ich, daß ich schon 'ne Grundversion fast fertig hätte, aber nachdem ich merkte, daß da doch was etwas anderes laufen kann ... nja, nun muß ich es doch irgendwie anders lösen. :cry: |
Re: himXML (gesprochen himix ML)
Wie gesagt, XPath wird noch etwas dauern, da dieses Aufgrund der Komplexität nich so einfach umzusetzen ist.
In der Zwischenzeit hab ich aber schonmal die Serialisierungen überarbeitet. - Variant-(De)Serialisierung ist fertig - ![]() - Record-Deserialisierung ist grad in arbeit (muß komlett geändert werden, da sich die Serialisierung änderte) - die Objektserialisierung kommt danach dran, hat aber schon einige Änderungen erhalten und Aufgrund neuer ![]() ein Update der Dateien wird es die nächsten Tage geben (wollte nur schonmal was sagen, bevor ich's vergeß) mein D2010 sollte auch bald ankommen und dann werd' ich mal sehn was die neue RTTI hierfür (Record-Analyse und Co.) zu bieten hat. Record/Array-Serialisierung:
Delphi-Quellcode:
je nach Einstellung würde z.B. eines der folgenden Ergebnisse entstehen:
Var Test: TSearchRec;
XML: TXMLFile; RI, RIx: TXMLSerializeRecordInfo; SL: TStrings; // einfach nur den Record mit irgendetwas befüllen FindFirst(Application.ExeName, faAnyFile, Test); FindClose(Test); XML := TXMLFile.Create; Try RI := TXMLSerializeRecordInfo.Create; Try RI.SaveTypeInfos := True; RI.Add('Time', rtInteger); RI.Add('Size', rtInt64); RI.Add('Attr', rtInteger); RI.Add('Name', rtString); RI.Add('Exclude', rtInteger); RI.Add('Handle', rtLongWord); RIx := RI.Add('Data', rtRecord); RIx.Add('Attributes', rtLongWord); RIx.Add('Creation', rtWord64BE); RIx.Add('LastAccess', rtWord64BE); RIx.Add('LastWrite', rtWord64BE); RIx.Add('FileSize', rtWord64LE); RIx.Add('Reserved0', rtLongWord); RIx.Add('Reserved1', rtLongWord); RIx.Add('FileName', rtCharArray, 260); RIx.Add('Alternate', rtCharArray, 14); // RI.Parse('I"Time" I8"Size" I"Attr" S"Name" I"Exclude" W4"Handle" R"Data" (' // + 'W4"Attributes" WE"Creation" WE"LastAccess" WE"LastWrite" IX"FileSize"' // + 'W4"Reserved0" W4"Reserved1" C260"FileName" C14"Alternate" )'); // RI.Parse('I I8 I S I W4 R ( W4 WE WE WE WX W4 W4 C260 C14 )'); // RI.Parse('ii8isiw4r(w4wewewewxw4w4c260c14)'); XML.AddNode('TestRec').Serialize(Test, RI); Finally RI.Free; End; XML.SaveToFile('Test.xml'); Finally XML.Free; End; //type // TFileName = type String; // THandle = LongWord; // TWin32FindData = record // dwFileAttributes: DWORD; // ftCreationTime: TFileTime; // ftLastAccessTime: TFileTime; // ftLastWriteTime: TFileTime; // nFileSizeHigh: DWORD; // nFileSizeLow: DWORD; // dwReserved0: DWORD; // dwReserved1: DWORD; // cFileName: array[0..259] of Char; // cAlternateFileName: array[0..13] of Char; // end; // // TSearchRec = record // Time: Integer; // Size: Int64; // Attr: Integer; // Name: TFileName; // ExcludeAttr: Integer; // FindHandle: THandle; // FindData: TWin32FindData; // end;
XML-Code:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<xml> <TestRec> <Time himxml:type="LongInt">998079892</Time> <Size himxml:type="Int64">978432</Size> <Attr himxml:type="LongInt">8224</Attr> <Name himxml:type="WideString">Test.exe</Name> <Exclude himxml:type="LongInt">0</Exclude> <Handle himxml:type="LongWord">4294967295</Handle> <Data himxml:type="Record"> <Attributes himxml:type="LongWord">8224</Attributes> <Creation himxml:type="Word64">129031275541718750</Creation> <LastAccess himxml:type="Word64">129039794795625000</LastAccess> <LastWrite himxml:type="Word64">129039794795625000</LastWrite> <FileSize himxml:type="Word64LE">978432</FileSize> <Reserved0 himxml:type="LongWord">0</Reserved0> <Reserved1 himxml:type="LongWord">0</Reserved1> <FileName himxml:type="WideCharArray">Test.exe</FileName> <Alternate himxml:type="WideCharArray"/> </Data> </TestRec> </xml> <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <xml> <TestRec> <Time>998079912</Time> <Size>978432</Size> <Attr>8224</Attr> <Name>Test.exe</Name> <Exclude>0</Exclude> <Handle>4294967295</Handle> <Data> <Attributes>8224</Attributes> <Creation>129031275541718750</Creation> <LastAccess>129039795155312500</LastAccess> <LastWrite>129039795155312500</LastWrite> <FileSize>978432</FileSize> <Reserved0>0</Reserved0> <Reserved1>0</Reserved1> <FileName>Test.exe</FileName> <Alternate/> </Data> </TestRec> </xml> <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <xml> <TestRec> <rec:0>998080983</rec:0> <rec:1>978432</rec:1> <rec:2>8224</rec:2> <rec:3>Test.exe</rec:3> <rec:4>0</rec:4> <rec:5>4294967295</rec:5> <rec:6> <rec:0>8224</rec:0> <rec:1>129031275541718750</rec:1> <rec:2>129039812850781250</rec:2> <rec:3>129039812850781250</rec:3> <rec:4>978432</rec:4> <rec:5>0</rec:5> <rec:6>0</rec:6> <rec:7>Test.exe</rec:7> <rec:8/> </rec:6> </TestRec> </xml> |
himXML (gesprochen himix ML)
Hallo Himitsu,
ich habe himXml (v0.983) gegen SimpleXML bzw. NativXML getestet. Ich habe viele sehr kleine XML-Dateien (1168 Dateien, UTF-8, 3kB..10kB). Bei diesem Test ist mir aufgefallen, dass sowohl SimpleXML als auch NativXML die Dateien merklich schneller parsen, als himXml. Bei SimpleXML habe ich mir mal die Mühe gemacht das Ganze nach Delphi 2009 zu portieren. SimpleXML und himXml laufen nun also beide mit Unicode-Strings. Trotzdem ist SimpleXML um Faktor 5 schneller (der Hash wird bei meiner Implementation bei jeder Datei neu aufgebaut - Bei der ursprünglich Implementation war dies nicht der Fall - macht SimpleXML aber nur 10% langsamer). Wenn ich die Units unter Delphi 2007 teste (SimpleXML dann mit Widestrings) komme ich zu ähnlichen Ergebnissen. Hast Du einen Tipp in welcher Richtung ich nach dem Performance-Fresser suchen könnte? |
Re: himXML (gesprochen himix ML)
Daß diese schneller sind, stimmt.
Ist auch in meinem Testprogramm (himXML\demos\CheckLibs.dpr) erkennbar, allerdings solltest du mal sehn, wie diese beiden Libs seit D2009 reagieren (da sind/waren dann erstmal Unmassen an Compilerwarungen). Es ist schön, daß SimpleXML auf D2009 portiert hast. Hast du dieses komplett auf Unicode umgestellt oder nur die Schnittstellen? 1. dann kommt es jetzt wohl nur noch mit Unicode-XML-Dateien klar 2. dann kommt es nur mit Ansi-XML-Dateien klar Das normale SimpleXML kann im Unicode-Modus eigentlich nur Unicode-Dateien verarbeiten und ansonsten nur Ansi-Dateien, wobei man da Extern für die (De)Codierung (in den AnsiStrings) sorgen muß. Also praktisch was es ursprünglich schon unicodetauglich, aber es funktionierte nicht so richtig. Du kannst aber gern mal die Unicode-Versionmit hochladen. Es gibt bestimmt welche, die sich darüber freuen würden. Der Overhead bei mir kommt vorallem von der entsprechenden Dekodierung, da die Dateien auch unterschiedlich kodiert sein können, was diese Libs garnicht oder nur teilweise beachten. Abgesehn davon laden diese die Dateien komplett in den RAM, bevor sie parsen. himXML ließt die Dateien "nur" stückchenweise ein, welches natürlich auch noch ein bissl bremst, aber dafür Speicher spart und der Parser selber kommt auch mit größeren Dateien von mehrere Terabyte locker klar. Versuch es also auch mal mit größeren Dateien. :zwinker: Zitat:
Aber im Vergleich mit MSXML sind diese Libs so oder so alle extrem flott. :stupid: Ein grundsätzliches Problem, welches es mit vielen dieser kleinen Libs gibt, daß sie seit vielen Jahren nicht mehr weiterentwickelt/gewartet werden. So darf/muß man sich dann selber damit rumschlagen und es erstmal zum Laufen bekommen. Ich hab jetzt schon versucht es halbwegs zukunftssicher zu gestalten. So mußte nur ein kleiner Denkfehler (2 Codestellen) behoben werden und es lief unter D2010 und in den nächsten Delphi-Versionen rechne ich (hoffentlich) mit noch weniger Problemen. PS: laut der NativeXML-Webseite schaft dieses ~1Mb/sec ... ich hab grad 'ne kleine 230 MB XML-Datei in etwa 25 Sekunden in mein himXML eingelesen, das macht dann 9 MB/s (mit D7 kompilert geht's noch schneller). (gut, mein Rechner ist gut doppelt so schnell, wie deren 1.5GHz P3-Testrechner, also sagen wir mal ~2 MB/s) |
Re: himXML (gesprochen himix ML)
Zitat:
Danke erstmal für die Hinweise. |
Re: himXML (gesprochen himix ML)
Was ich witzig finde:
in D4 bis D2007 kann man SimpleXML entweder im Ansi-Modus (inklusive UTF-8, aber ohne Dekodierung) laufen lassen, oder im Unicode-Modus ( einfach diesen Befehl aktivieren > { $DEFINE XML_WIDE_CHARS} ). Wobei hier dann nur noch Unicode-Dateien lesbar sind und andere XML-Parser durchdrehen da dieser die Datei zwar im Unicode (UTF-16) speichert, aber standardmäßig "windows-1251" als Standardencoding im "Header" speichert. Und seit D2009 ist SimpleXML nativ nur noch Unicode (wobei viele Stellen nicht korrekt arbeiten) und wenn man jetzt aber zusätzlich noch { $DEFINE XML_WIDE_CHARS} aktiviert, denn arbeitet es überhaupt nicht mehr, da es das Unicode dann als Ansi ansieht und versucht es nochmals in Unicode umzuwandeln z.B.:
Delphi-Quellcode:
FBufPtr ist schon PChar, wird als AnsiChar genommen und nochmals in WideChar umgewandlet.
{$IFDEF XML_WIDE_CHARS}
CurChar := AnsiToUnicode(FBufPtr^); {$ELSE} CurChar := FBufPtr^; {$ENDIF} also bis D2007 noch nutzbar und danach muß man ganz schön aufpassen. PS: in den JEDIs gibt/gab (?) es auch ein "SimpleXML" hab hier zwei "ältere" Dateien JvSimpleXml.pas (2002) JclSimpleXml.pas (01. 2009), aber da ich die JEDIs grad nicht installiert hab, kann ich nichts weiteres dazu sagen. |
himXML (gesprochen himix ML)
Das Teil im Jedi-Projekt ist allerdings schon nicht mehr besonders "Simple", weil es diverse Jedi-Units benutzt. Daraus folgt dann, dass man im Grunde am besten das gesamte Projekt installiert. Nicht gerade das, was man sich so vorstellt, wenn man "nur mal schnell" eine kleine XML-Datei auslesen will.
|
Re: himXML (gesprochen himix ML)
Dann solltest du dir nicht, KDS XML, OmniXML und Co. ansehn. :lol:
(bei mir reicht im Grunde eine Datei ... die himXMLCheck.inc könnte man weglassen und die Strings der himXML_Lang.pas integrieren) Wobei das Simple doch wohl eigentlich mehr auf "einfache" Benutzung hinweisen soll, aber so einfach ist einiges davon nicht gerade. :? |
Re: himXML (gesprochen himix ML)
Hab nicht alle Posts gelesen, aber gibt's eventuell noch eine mit D7 kompatible Version?
|
Re: himXML (gesprochen himix ML)
'ne kleine Kollektion und diese werde ich auch mal im Eingangspost verlinken.
Aktuell hab ich noch ein paar größere Umbauten vor mir, bzw. bin mitten drin, so daß es sich, vom Aufwand her, einfach nicht lohnt da jetzt schon eine weitere Version parallel verwalten zu wollen. Aber von Turbo/2006 bis 2010 sollte es jetzt erstmal laufen. :-D Zitat:
Zitat:
Zitat:
Hätte zwar noch ein Delphi 4 zum Testen, aber ich fürchte dort wird so wenig unterstützt, daß es wohl nicht gehn wird. Zitat:
Zitat:
|
Re: himXML (gesprochen himix ML)
In Post #1 liegt derzeit eine noch ungetestete Probeversion rum, welche sich zumindestens schonmal ohne Probleme in Delphi 7 kompilieren läßt.
|
Re: himXML (gesprochen himix ML)
Soo, diesesmal ist nicht allzuviel passiert (hatte aber sozusagen versprochen den Code schon jetzt mal hochzuladen)
- vorwiegend wurde an der Speicherveraltung rumgespielt - die ganzen Serialisierungsfunktionen wurden fast komplett überarbeitet - der Code wurde Downgegradet und sollte nun mindestens ab Delphi 7 arbeiten (Einiges ist aber erst ab Delphi 2006, bzw. TDE verfügbar) - vorallem die Demo CheckLibs wurde umgebaut Grund: ![]() und ![]() - und dann wurden auch gleich mal die anderen XML-Libs upgegradet (Grund hierfür kommt gleich) Ja, nachdem ich sowieso schonmal eine der Libs erneuerte, ![]() hab ich das bei den Anderen auch mal gemacht und zusätzlich noch welche nachgerüstet. Also wurde gleich mal alles etwas umgestellt. Beim Umsehen fiel mir auf, daß einige Libs nun doch wieder aktualisiert werden, sei es von Fremden (siehe SimpleXML) oder den Erstellern persönlich und das nachdem sich an vielen Stellen seit Jahren nichts mehr regte. Enthalten sind jetzt alle Dateien und Links zu diesen Libs (siehe Ordner "other" und der CheckLibs-Demo). ThaXML v1.0 12.01.2003 ist vollkommen veraltet und läuft ab D2009 nur noch zufällig ab und zu mal und manchmal erstellt es defekte und vorallem nicht Codierungskonforme XML-Dateien OmniXML v2010-01-03 nja, obwohl diese Lib anscheinend gutes Potential hatte SimpleXML v2010-01-03 samso läuft es nun auch unter D2009 und vermutlich D2010 (teste ich demnächst mal) XMLLib v1.90 09.12.2009 joar, auch Muetze1 hat doch nochmal viel an seiner Lib gemacht @Muetze1: ich dachte du wolltest "nur" noch an deiner geheimen neuen Lib basteln? und du hast Recht, für größere Dateien ist deine Lib nicht wirklich geeignet, aber was soll's. KDS XML v1.41 2004-04-07 liegt nur bei, aber Aufgrund des Alters und da bisher keine Nachfrage bestand, ist sie nicht in die CheckLib integriert XML Parser v1.0.19 2009-12-31 sobald ich meinen SAX-Parser (TSAXReader) wieder in Betrieb nehm, wird dieser auch mit in die CheckLibs integriert ... solange liegt er einfach nur so daneben rum und dann noch MSXML, XercesXML und OpenXML wobei MSXML ja wohl (bei halbwegs "normalen" Dateigrößen) das Langsamste und der größte Speicherfresser ist. PS: beim Löschen von Nodes und mit doNodeAutoIndent ergibt sich krankes Bid, denn alle Formatierungen bleiben erhalten, welches in Test 2 eine rießige Lücke aus Leerzeichen und Zeilenumbrüchen zurückläßt und die Datei so auf die Doppelte größe aufbläht :shock: PS: falls jemand ein schönes Testszenaio hat, welches halbwegs einheitlich auf alle integrierten Libs anwendbar ist, dann kann er/sie sich gerne mal melden und hier noch die Ausgabe der CheckLib.dpr
Code:
SetProcessAffinityMask: OK
precreating used strings - do not create and convert this within the measuring create: 40 ***** Information ************************************************************* mem : new allocated virtual memory filesize : size | size after reformatting by himXML ***** Test 1 ****************************************************************** fill TXMLFile with 10.000 nodes and save this into a file create: 0 fill: 7 save: 4 free: 3 mem: 1mb filesize: 148.961|148.961 fill MS-XML-DOM with 10.000 nodes and save this into a file create: 4 fill: 12.959 save: 55 free: 48 mem: 11mb filesize: 148.962|148.961 fill ThaXML with 10.000 nodes and save this into a file create: 0 fill: 4 save: 8 free: 24 mem: 1mb filesize: 158.945|148.944 fill SimpleXML with 10.000 nodes and save this into a file create: 0 fill: 4 save: 7 free: 1 mem: 1mb filesize: 138.943|148.944 fill XMLLib with 10.000 nodes and save this into a file create: 0 fill: 140 save: 33 free: 43 mem: 1mb filesize: 158.963|148.961 ***** Test 2 ****************************************************************** fill TXMLFile with 10.000 nodes, delete 8.000 nodes and save this into a file create: 0 fill: 6 delete: 304 save: 1 free: 0 filesize: 28.961|28.961 fill MS-XML-DOM with 10.000 nodes, delete 8.000 nodes and save this into a file create: 1 fill: 12.981 delete: 81.925 save: 53 free: 41 filesize: 60.962|28.961 fill ThaXML with 10.000 nodes, delete 8.000 nodes and save this into a file create: 0 fill: 4 delete: 1.601 save: 2 free: 1 filesize: 30.945|28.944 fill SimpleXML with 10.000 nodes, delete 8.000 nodes and save this into a file create: 0 fill: 4 delete: 91 save: 1 free: 0 filesize: 26.943|28.944 fill XMLLib with 10.000 nodes, delete 8.000 nodes and save this into a file create: 0 fill: 141 delete: 523 save: 7 free: 4 filesize: 30.963|28.961 ***** Test 3 ****************************************************************** fill TXMLFile with 10.000 nodes with attributes and save this into a file create: 0 fill: 15 save: 13 free: 5 mem: 1mb filesize: 267.851|267.851 fill MS-XML-DOM with 10.000 nodes with attributes and save this into a file create: 1 fill: 15.534 save: 59 free: 55 mem: 4mb filesize: 267.852|267.851 fill ThaXML with 10.000 nodes with attributes and save this into a file create: 0 fill: 10 save: 24 free: 25 mem: 1mb filesize: 277.835|267.834 fill SimpleXML with 10.000 nodes with attributes and save this into a file create: 0 fill: 7 save: 12 free: 3 mem: 1mb filesize: 257.833|267.834 fill XMLLib with 10.000 nodes with attributes and save this into a file create: 0 fill: 144 save: 50 free: 46 mem: 1mb filesize: 277.853|267.851 ***** Test 4 ****************************************************************** fill TXMLFile with 100.000 nodes, save into and load this from a file create: 0 fill: 73 save: 35 free: 41 mem: 11mb create: 0 load: 180 free: 36 filesize: 1.588.961|1.588.961 fill MS-XML-DOM with 100.000 nodes, save into and load this from a file create: 1 fill: 1.338.466 save: 145 free: 504 mem: 143mb create: 0 load: 333 free: 94 filesize: 1.588.962|1.588.961 fill ThaXML with 100.000 nodes, save into and load this from a file create: 0 fill: 44 save: 110 free: 2.692 mem: 12mb create: 0 load: 403.349 free: 2.692 filesize: 1.688.945|1.588.944 fill SimpleXML with 100.000 nodes, save into and load this from a file create: 0 fill: 53 save: 73 free: 24 mem: 4mb create: 0 load: 163 free: 23 filesize: 1.488.943|1.588.944 fill XMLLib with 100.000 nodes, save into and load this from a file create: 0 fill: 12.398 save: 325 free: 3.869 mem: 18mb create: 0 load: 12.099 free: 3.869 filesize: 1.688.963|1.588.961 ***** Test 5 ****************************************************************** fill TXMLFile with 100.000 nodes with attributes and search nodes create: 0 fill: 15 search: 1.899 free: 5 fill MS-XML-DOM with 100.000 nodes with attributes and search nodes create: 8 fill: 15.348 search: 151.316 free: 57 fill ThaXML with 100.000 nodes with attributes and search nodes create: 0 fill: 11 search: 11.159 free: 25 fill SimpleXML with 100.000 nodes with attributes and search nodes create: 0 fill: 7 search: 430 free: 3 fill XMLLib with 100.000 nodes with attributes and search nodes create: 0 fill: 144 search: 2.850 free: 48 ***** Test 6 ****************************************************************** fill TXMLFile with 3.000.000 nodes, save into and load this from a file create: 0 fill: 12.073 save: 11.994 free: 2.327 mem: 1.536mb create: 0 load: 28.524 free: 2.164 filesize: 315.777.851|315.777.851 fill MS-XML-DOM with 3.000.000 nodes, save into and load this from a file error: das ist wirklich keinem zumutbar fill ThaXML with 3.000.000 nodes, save into and load this from a file error: EOutOfMemory wrde sich so ab 2.000.000 melden error: ab etwa 500.000 braucht .Free ewig und es steigt expotentiel an es sind hiermit also efektiv nicht viel mehr als 200.000 m”glich fill ThaXML with 200.000 nodes, save into and load this from a file create: 0 fill: 546 save: 2.349 free: 11.736 mem*15: 1.496mb filesize: 22.377.835|error Ungültige Zeigeroperation error: das Laden wrde ewig brauchen fill ThaXML with 15.000 nodes, save into and load this from a file create: 0 fill: 38 save: 181 free: 59 create: 0 load: 113.716 free: 59 filesize: 1.642.835|error Ungültige Zeigeroperation fill SimpleXML with 3.000.000 nodes, save into and load this from a file create: 0 fill: 14.264 save: 7.752 free: 2.158 mem: 1.365mb create: 0 load: 30.214 free: 2.969 filesize: 312.777.833|315.777.834 fill XMLLib with 3.000.000 nodes, save into and load this from a file [color=silver]>>>> nach 'ner 1/2 Stunde abgebrochen, aber da wäre eh bald ein OutOfMemory gekommen[/color] |
Re: himXML (gesprochen himix ML)
Hallo Himi,
mal ne "dumme" Frage...was bringt mir XML?..ich lese dies nun haeufig hier und sehe in dieser Struktur keine Vorteile gegenueber einer "Memory-Table"bzw. lokalen Database( integriert in Exe)...Ist diese Datenspeicherung/bearbeitung eher für Internetanwendungen gedacht?(da habe ich aber auch schon o.g. Datenbanken genutzt????) :gruebel: Sorry, falls ich vom Thema abschweife..reine Interesse..oder sollte ich einen neuen Thread eroeffnen? |
Re: himXML (gesprochen himix ML)
Zitat:
1. Es ist von Menschen lesbar 2. Es ist erweiterbar. Man kann z.B. Tags hinzufügen und die Datei bleibt trotzdem lesbar. Das stellt Kompatiblität sicher. 2. Es ist weit verbreitet, wird von vielen Programmen unterstützt und für praktisch jede Programmiersprache stehen entsprechende Bibliotheken bereit. XML selbst ist als Beschreibungssprache nicht unbedingt das eleganteste, was man sich vorstellen kann, vor allem, weil es recht viel Overhead erzeugt. Der große Vorteil von XML ist die Kompatiblität: Du kannst auch in neueren Programmversionen Dateien, die mit älteren Versionen erstellt wurden, problemlos einlesen, ohne sie erst konvertieren zu müssen. Umgekehrt kannst du sogar mit älteren Programmen Dateien lesen, die mit neueren Versionen erstellt wurden. Selbst wenn in 20 Jahren dein Programm selbst schon nicht mehr auf aktuellen Rechnern läuft, wird man die XML-Dateien immer noch lesen können. |
Re: himXML (gesprochen himix ML)
Zitat:
P.S.: ist wirklich nicht "Anti" maessig...ich hab nur seit 30 Jahren..vom Grossrechner(selbst Drucklisten) ueber Turbo Pascal - Delphi..alles in eine CSV(Excel kompatible eben) mit leichtigkeit konvertieren koennen..deshalb meine Frage (Sorry wenns bissl komisch klingt) [edit] PS[/Edit] |
Re: himXML (gesprochen himix ML)
CSV, INI und XML sind soweit schonmal miteinander verwandt, daß sie ohne spezielle Programme direkt lesbar sind.
* CSV kann aber erstmal nur eine Tabelle enthalten * INI im Grunde mehrere Tabellen/Sektionen * XML kann ganze Bäume enthalten, da man dort bliebig verschachteln kann. * bei Datenbanken braucht man irgendeinen Server (und wenn es ein Lokaler ist) * Binärdateien benötigen einen speziellen Interpreter und lassen sich "schlecht" erweitern/ändernund sind danach erstmal nicht mehr kompatibel untereinander * wobei Datenbanken im Grunde auch nur binäre Dateien sind, welche aber von Fremdcode verwaltet werden |
Re: himXML (gesprochen himix ML)
Zitat:
|
Re: himXML (gesprochen himix ML)
Ein Vorteil von XML gegenüber CSV ist auch, dass in XML die Tag-Namen Aufschluss darüber geben, was eigentlich wo gespeichert wird. Bei CSV fehlen solche Meta-Informationen, was es u.U. schwierig macht, die Daten einzulesen, wenn keine Dokumentation vorhanden ist.
|
Re: himXML (gesprochen himix ML)
Zitat:
CSV besteht erstmal nur aus namenlosen Spalten > füge irgendwo mal eine Spalte ein oder laß eine weg ... schon geht nix mehr |
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:31 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz