![]() |
Probleme beim Arbeiten mit XML und Double-Werten
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
der folgende Code führt unter Delphi-Seattle und Delphi-Rio (Update 3) zu unterschiedlichen Ausgaben:
Delphi-Quellcode:
Ausgabe des Programms mit Delphi-Seattle kompiliert:
procedure TForm1.FormCreate(Sender: TObject);
var node: IXMLNode; doubleValueInput: Double; doubleValueOutput: Double; begin node := NewXMLDocument.GetDocBinding('Value', TXMLNode, '') as IXMLNode; doubleValueInput := 3.14; node.NodeValue := doubleValueInput; doubleValueOutput := node.NodeValue; Caption := Format('DoubleValueInput: %f NodeValue: %s, DoubleValueOutput: %f', [doubleValueInput, VarToStr(node.NodeValue), doubleValueOutput]); end;
Code:
Ausgabe des Programms mit Delphi-Rio kompiliert:
DoubleValueInput: 3,14, NodeValue: 3,14, DoubleValueOutput: 3,14
Code:
Ist Jemand diese Situation bekannt?
DoubleValueInput: 3,14, NodeValue: 3.14, DoubleValueOutput: 314
Was kann man dagegen tun? Wie sieht das Ergebnis unter Delphi-Sydney kompiliert aus? Vielen Dank im Voraus. Ciao Heza PS. Den Code des Test-Programms habe ich angehängt. |
AW: Probleme beim Arbeiten mit XML und Double-Werten
Tja, im Prinzip ist das aktuelle Verhalten "eigentlich" richtig. :angle:
* in der XML wird platformunabhängig gespeichert (Englisch mit Dezimalpunkt) * beim Auslesen wird aus dem Text ein Variant/OleVariant * und Variant/OleVariant nimmt beim Umwandeln die aktuellen Systemeinstellungen (nja, eigentlich falsch ... der sollte besser die Programmeinstellungen nehmen aber so lange du sie nicht änderst, passt es) * und da das bei dir ein Dezimalkomma ist (Deutsch), wird der Punkt ignoriert Double-from-XML: TXMLNode.GetNodeValue -> GetText -> _VarToReal -> _VarToDouble -> varOleStr:VarToDoubleAsString - VarR8FromStr(VAR_LOCALE_USER_DEFAULT) Double-to-XML: _VarFromReal -> NodeValueToText -> varDouble:XmlFloatToStrExt -> _VarToDouble -> XmlFloatToStr -> FloatToStr(XmlFormatSettings) -> SetText Leider ist es nicht möglich, einem Variant/OleVariant eine eigene Locale (FormatSettings) mitzugeben, so das es im Programm überall gleich behandelt wird. * XMLString-to-Variant und Variant-to-Double macht hier der Variant (sprachabhängig) * Double-to-Variant macht auch der Variant (sprachabhängig), aber dann Variant-to-XMLString macht die XML-Komponente (sprachunabhängig) XML-Komponente: ist zwar richtig, aber leider falsch, da es beim Auslesen nicht auch so gemacht wird, aber geht auch nicht anders. Die XML-Komponente kann nicht einfach den "." im String in ein "," tauschen, damit Variant-to-Double "richtig" arbeiten kann, denn was wäre, wenn der Punkt kein Dezimalpunkt, sondern einfach nur ein Punkt wäre. (z.B. eine Versionsnummer und keine Dezimalzahl)
Delphi-Quellcode:
uses Xml.XMLIntf, Xml.XMLDoc;
procedure TForm15.FormCreate(Sender: TObject); var node: IXMLNode; doubleValueInput: Double; doubleValueOutput: Double; begin node := NewXMLDocument.GetDocBinding('Value', TXMLNode, '') as IXMLNode; doubleValueInput := 3.14; node.NodeValue := doubleValueInput; doubleValueOutput := node.NodeValue; Memo1.Text := Format('DoubleValueInput: %f NodeText: %s, NodeValue: %s, DoubleValueOutput: %f', [doubleValueInput, node.Text, VarToStr(node.NodeValue), doubleValueOutput]) + sLineBreak + Node.XML; end;
Code:
Was kommt denn im Seattle raus?
DoubleValueInput: 3,14 NodeText: 3.14, NodeValue: 3.14, DoubleValueOutput: 314,00
<Value>3.14</Value> Nja, Hier wirst du wohl oder übel selber den Zahl-String in einen Double konvertieren müssen. Mit fällt auch keine "gute" Lösung ein, das beim NodeValue reparieren zu können. (außer du stellst dein Windows auf Englisch um oder siehe Tipp)
Delphi-Quellcode:
Tipp: Bau dir für IXMLNode einen Record-Helper, welcher ein .AsFloat-Property hat und wo intern in beiden Richtungen gleich gearbeitet wird.
D := XmlStrToFloat(node.Text);
// oder D := StrToFloat(node.Text, TFormatSettings.Create('en-US'));
Delphi-Quellcode:
Die ...Ext beachten auch NaN, Infinity und NegInfinity.
// unit Xml.xmlutil;
function XmlStrToFloat(const Value: string): Extended; function XmlFloatToStr(const Value: Extended): string; function XmlStrToFloatExt(const Value: string): Extended; function XmlFloatToStrExt(const Value: Extended): string; |
AW: Probleme beim Arbeiten mit XML und Double-Werten
Hallo Himitsu,
Danke für die ausführliche Antwort. Das war zwar nicht das was ich hören bzw. lesen wollte, ist aber für mich nachvollziehbar. Es sollte gerade ein umfangreiches Projekt von Seattle nach Rio migriert werden. Da müssen jetzt erst mal alle XML verarbeitende Stellen untersucht werden, ob sie von dieser Änderung der XML-Verarbeitung zwischen Seattle und Rio betroffen sind. :roll: @Alle Machen es da eigentlich andere XML-Bibliotheken besser? Ciao HeZa |
AW: Probleme beim Arbeiten mit XML und Double-Werten
Das "Problem" hier ist, dass es einige Teile im Delphi gibt (wie z.B. die Konvertierung von Variant in den XMLString, aber das Andersrum fehlt) und dahnter eine Fremdkomponente von Microsoft sich versteckt, bzw. "Eine" ist es garnicht, da dort unterschiedliche Libraries und Versionen gekapselt sein können (z.B. MS-XML, OmniXML usw.), welche teilweise sich auch im Verhalten unterscheiden.
![]() Und ja, es gibt auch andere XMLLibs. (SuFu) Die z.B. komplett in Pascal geschrieben sind und dann auf beiden Seiten gleich arbeiten können. Achtung, wenn sie ebenfalls Variant einsetzen, dann gibt es da die gleichen Probleme. Aber mit Funktionen/Erweiterungen ala AsFloat geht es. Es gibt auch Libs, welche die Sprache nicht beachten, also im deutschen Windows 3,14 speichern, anstatt 3.14 , was "jetzt" erstmal super funktioniert, welches dann aber knallt, wenn diese XML in einem anderssprachigem Windows geladen/gespeichert wird. Ohne zusätzlich, z.B. als Attribut, in der XML zu speichern, dass dieses ein "Float" ist, dann ist eine automatische Behandlung/Konvertierung (Variant und Co.) garnicht möglich, außer man gibt eben programmseitig das Verhalten vor (AsFloat). Eine Heuristik, zum erkennen der "." und ",", also ob es nun ein Dezimalpunkt oder ein Tausenderpunkt ist, ist auch nicht zielführend, denn ist 3.142 nun Pi oder doch eine 3000? Es gibt auch XML-Object-Mapping-Komponenten, welche die Typen richtig beachten. |
AW: Probleme beim Arbeiten mit XML und Double-Werten
Zitat:
Aber ein Record-Helper geht scheinbar für Interfaces nicht. TXmlNode macht auch keinen Sinn. Hat da jemand noch einen Trick. Ich komme gerade nicht drauf. Nur mal so als Grundidee:
Delphi-Quellcode:
Liebe Grüße
unit XmlHelper;
interface uses System.SysUtils, Xml.XMLDoc; type XmlNodeHelper = record helper for IXmlNode Function AsFloat() : Extended; end; var XmlFormatSetting : TFormatSettings; implementation { XmlNodeHelper } Function XmlNodeHelper.AsFloat() : Extended; var sValue : String; begin sValue := Self.Text; // <- Einfach nur zu Debugging-Zwecken in extra Variable Result := StrToFloatDef(sValue, 0, XmlFormatSetting); end; initialization XmlFormatSetting := TFormatSettings.Create('en-US'); end. Incocnito |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:05 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