I get a System.FormatException thrown when i try to parse XML into an object. As far as I can tell, it's due to the culture used in System.Xml.Serialization.XmlSerializer.Deserialize, wich expects a dot as the decimal character, but the xml contains a comma.
The object looks as follows:
public sealed class Transaction
{
[XmlElement("transactionDate")]
public DateTime TransactionDate { get; set; }
[XmlElement("transactionAmount")]
public decimal Amount { get; set; }
[XmlElement("transactionDescription")]
public string Description { get; set; }
[XmlElement("transactionType")]
public int Type { get; set; }
public static Transaction FromXmlString(string xmlString)
{
var reader = new StringReader(xmlString);
var serializer = new XmlSerializer(typeof(Transaction));
var instance = (Transaction) serializer.Deserialize(reader);
return instance;
}
}
The xml:
<transaction>
<transactionDate> 2013-07-02 <transactionDate>
<transactionAmount>-459,00</transactionAmount>
<transactionDescription>description</transactionDescription>
<transactionType>1</transactionType>
</transaction>
I've made it work by introducing a second property that parses the first using my own culture:
namespace MyNamespace
{
[XmlRoot("transaction"), XmlType("Transaction")]
public sealed class Transaction
{
[XmlElement("transactionDate")]
public DateTime TransactionDate { get; set; }
[XmlElement("transactionAmount")]
public string Amount { get; set; }
public decimal AmountAsDecimal {
get
{
decimal value;
Decimal.TryParse(Amount, NumberStyles.Any, CultureInfo.CreateSpecificCulture("sv-SE"), out value);
return value;
}
}
[XmlElement("transactionDescription")]
public string Description { get; set; }
[XmlElement("transactionType")]
public int Type { get; set; }
public static Transaction FromXmlString(string xmlString)
{
var reader = new StringReader(xmlString);
var serializer = new XmlSerializer(typeof(Transaction));
var instance = (Transaction) serializer.Deserialize(reader);
return instance;
}
}
}
which exposes an extra property that i don't want there.
So my question is: is there another way to do this, without iterating over each element and parsing/assigning it to the object "manually"?
If you know the culture that the XML was generated in, one easy solution is to switch the current thread's culture to that culture prior to deserializing.
What you can do instead is have a property that will be used to serialize/deserialize the
decimal
.See: Partially deserialize XML to Object
This way you can get/set the
Amount
without needing to worry about how it is serialized. Since this is a DTO you can create another class without theAmountSerialized
as your domain object (and use something like AutoMapper to make conversion painless).Usage:
Also there was a typo in the ending tag for
transactionDate
.XML serializer uses a standardized Number and DateTime format, the standard is defined in the W3C schema datatype specification http://www.w3.org/TR/xmlschema-2/.
Don't expect
XmlSerializer
to pay attention to the thread'sCultureInfo
, it intentionally uses a standardized format to ensure you can serialize/deserialize independent of the culture/locale.