AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein XML Delphi Probleme beim Arbeiten mit XML und Double-Werten

Probleme beim Arbeiten mit XML und Double-Werten

Ein Thema von HeZa · begonnen am 8. Apr 2021 · letzter Beitrag vom 17. Mär 2022
Antwort Antwort
HeZa

Registriert seit: 4. Nov 2004
Ort: Dortmund
182 Beiträge
 
Delphi 10 Seattle Professional
 
#1

Probleme beim Arbeiten mit XML und Double-Werten

  Alt 8. Apr 2021, 18:48
Hallo,

der folgende Code führt unter Delphi-Seattle und Delphi-Rio (Update 3) zu unterschiedlichen Ausgaben:
Delphi-Quellcode:
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;
Ausgabe des Programms mit Delphi-Seattle kompiliert:
Code:
DoubleValueInput: 3,14, NodeValue: 3,14, DoubleValueOutput: 3,14
Ausgabe des Programms mit Delphi-Rio kompiliert:
Code:
DoubleValueInput: 3,14, NodeValue: 3.14, DoubleValueOutput: 314
Ist Jemand diese Situation bekannt?
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.
Angehängte Dateien
Dateityp: zip XmlNodeDoubleTest.zip (54,1 KB, 1x aufgerufen)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.017 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.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

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

Registriert seit: 4. Nov 2004
Ort: Dortmund
182 Beiträge
 
Delphi 10 Seattle Professional
 
#3

AW: Probleme beim Arbeiten mit XML und Double-Werten

  Alt 9. Apr 2021, 07:33
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.

@Alle
Machen es da eigentlich andere XML-Bibliotheken besser?

Ciao HeZa
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Probleme beim Arbeiten mit XML und Double-Werten

  Alt 9. Apr 2021, 10:02
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.

https://www.delphipraxis.net/20455-a...zum-msxml.html


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.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu ( 9. Apr 2021 um 10:06 Uhr)
  Mit Zitat antworten Zitat
Incocnito

Registriert seit: 28. Nov 2016
208 Beiträge
 
#5

AW: Probleme beim Arbeiten mit XML und Double-Werten

  Alt 17. Mär 2022, 14:01
...
Tipp: Bau dir für IXMLNode einen Record-Helper, welcher ein .AsFloat-Property hat und wo intern in beiden Richtungen gleich gearbeitet wird....
Da wir gerade InHouse genau dieses Problem auch haben, hatte ich überlegt diesen Record-Helper zu bauen.

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:
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.
Liebe Grüße
Incocnito
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:33 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