I'm reading attribute fields in an XML document where the decimal point always is '.'
and the computer local may differ from this (in my own case it is ','
).
I tried to set the global FormatSettings.DecimalSeparator
to '.'
but it has no effect on the XML parser. This is a very compressed version of the problem.
_di_IXMLDocument Document;
_di_IXMLNode Node;
float Value;
Document = LoadXMLDocument("Test.xml");
Node = Document->DocumentElement;
FormatSettings.DecimalSeparator = '.';
Value = Node->GetAttribute("scale");
Assume this XML file.
<?xml version="1.0" encoding="utf-8"?>
<myroot scale="1.234">
</myroot>
After reading the attribute scale I always get the result striped on the '.' character resulting in Value = 1234 instead of 1.234.
The number of decimals are not constant, they can be 1 or 4 or anything in between. This also goes for the whole part, so dividing by 100 or 1000 will not solve the problem.
I would preferable have the OLEVariant to accept the '.'
as a decimal point (my local is ','
).
I had a look at SetLocalInfo()
but this will set the format for ALL applications. The getlocale()
function manipulates the current thread but I have not found a way to explicitly specify the character to use. It seems like it is only possible to select a code page or localization, as in a country.
EDIT
I tried to use setlocal()
and select English-US
as localization. Even if US are using '.'
as the decimal separator, the XML Parsers seems to ignore this.
If I manually change the '.'
to a ','
in the XML file, it works fine. But the XML file is a third party file, which I have no control of. So I really need to read it as it is with a '.'
decimal separator
This is a well-known problem with the way the IXMLNode.NodeValue
property handles floating-point numbers. It has nothing to do with the underlying XML engine (MSXML, etc).
The NodeValue
property getter returns an OleVariant
that contains the attribute value as a String
, not as a float
. You are then assigning that OleVariant
to a float
. The RTL performs a conversion using OS locale settings, not RTL locate settings, which is why FormatSettings
has no effect.
The NodeValue
property setter receives an OleVariant
as input. Passing a float
directly to it performs a conversion to a String
when inserting the value into the XML DOM, and that conversion is also not tied to FormatSettings
.
NodeValue
is locale-sensitive, but XML is not. The XML standard specifically outlines exactly how floating-point numbers must be formatted, which IXMLNode
does not take into account. So you will have to read/write floating-point values as String
values so that you can handle conversions yourself, eg:
TFormatSettings fmt = TFormatSettings::Create();
fmt.DecimalSeparator = '.';
fmt.ThousandSeparator = 0;
Value = StrToFloat(Node->Attributes["scale"], fmt);
TFormatSettings fmt = TFormatSettings::Create();
fmt.DecimalSeparator = '.';
fmt.ThousandSeparator = 0;
Node->Attributes["scale"] = FloatToStr(Value, fmt);