NSDecimalNumber to NSXML and Back, A Cocoa Bug
I’ve been working on processing the XML export Billable creates and have discovered a strange behavior which I think is a bug. Basically when you pass an NSDecimalNumber (or even a regular NSNumber according to others) to the NSXMLNode using the setObjectValue: method and create an XML file it uses E notation to represent the number. I don’t have a problem with this but for some numbers it doesn’t use a decimal symbol for numbers like 1.0 or 4.0. When you read the XML back in and turn these into NSDecimalNumbers using decimalNumberWithString: you get 10 and 40 respectively.
I’ve create a sample application to demo the behavior. It generates 300 random NSDecimalNumbers (incrementing by .1-.5 over time), the first column is what I’ve generated, the second is what it looks like in XML and the third is what it looks like after been read from the XML back into an NSDecimalNumbers using decimalNumberWithString:.

I think one work around is to scan the XML string representation for the number and if it’s missing a decimal insert on after the first character but have to do some test to see if it’ll work under all cases. If you have more information or suggestions please let me know.
UPDATE: I’ve added a second version of the program with two new columns. One for the result of my “insert period when missing hack” and the other to note if the hack was needed and if so did it work. I’ve added to the total numbers generated as well, included negative numbers, extremes and the magical zero. I think this hack (which is a category method of NSString titled decimalNumberValueUsingXMLHack: should work.
To all those submitting suggestions for how I can create a good XML file (and work around the bug), thanks — but the true bane of this issue (for me) is that I have bad XML in the wild and need to cope, hence the work around on processing the XML file.
Posted on: May 26, 2007 – 5:56 PM

3 Comments
I have a little code change that will get things working, but it has a possible gotcha. Since it’s small, I’ll just post the code here:
Starting at line 53 in your AppController.m file:
….
The gotcha is that if the user happens to change their locale, this could give bad values (I haven’t tested that, though).
If you’re not trying to retain the decimal point, you may be better off writing the stringValue of the NSDecimalNumber instead of letting NSXMLNode encode it (incorrectly) for you. For NSDecimalNumbers like ‘90.0’, this will turn them into ‘90’, but you may or may not care about that.
@Grahm: For future XML exports yes, but I need to process XML already out in the wild right now. Thanks for the note though.
Post a Comment | Comment RSS feed