0

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

Max Kielland
  • 5,627
  • 9
  • 60
  • 95
  • (This isn't a standard-XML question, it's specifically Microsoft and not portable. So my answer wasn't directly applicable, and I'll refer you to Microsoft.) – keshlam Mar 16 '14 at 02:20

1 Answers1

4

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);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thank you for the deep explanation. I ended up with a string conversion similar to your suggestion. You confirmed that it wasn't me that failed ;) – Max Kielland Mar 18 '14 at 02:23