Einzelnen Beitrag anzeigen

Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#2

AW: Probleme beim Arbeiten mit XML und Double-Werten

  Alt 8. Apr 2021, 20:09
Tja, im Prinzip ist das aktuelle Verhalten "eigentlich" richtig.

* 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:
DoubleValueInput: 3,14 NodeText: 3.14, NodeValue: 3.14, DoubleValueOutput: 314,00
<Value>3.14</Value>
Was kommt denn im Seattle raus?

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:
D := XmlStrToFloat(node.Text);
// oder
D := StrToFloat(node.Text, TFormatSettings.Create('en-US'));
Tipp: Bau dir für IXMLNode einen Record-Helper, welcher ein .AsFloat-Property hat und wo intern in beiden Richtungen gleich gearbeitet wird.
Delphi-Quellcode:
// 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;
Die ...Ext beachten auch NaN, Infinity und NegInfinity.
$2B or not $2B

Geändert von himitsu ( 8. Apr 2021 um 20:24 Uhr)
  Mit Zitat antworten Zitat