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"?
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's CultureInfo
, it intentionally uses a standardized format to ensure you can serialize/deserialize independent of the culture/locale.
What you can do instead is have a property that will be used to serialize/deserialize the decimal
.
See: Partially deserialize XML to Object
[XmlType("transaction")]
public sealed class Transaction
{
[XmlElement("transactionDate")]
public DateTime TransactionDate { get; set; }
[XmlIgnore]
public decimal Amount { get; set; }
[XmlElement("transactionAmount")]
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public string AmountSerialized
{
get
{
return Amount.ToString(CultureInfo.CreateSpecificCulture("sv-SE"));
}
set
{
decimal amount;
Decimal.TryParse(value, NumberStyles.Any, CultureInfo.CreateSpecificCulture("sv-SE"), out amount);
Amount = amount;
}
}
[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;
}
}
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 the AmountSerialized
as your domain object (and use something like AutoMapper to make conversion painless).
Usage:
var data = @"<transaction>
<transactionDate>2013-07-02</transactionDate>
<transactionAmount>-459,00</transactionAmount>
<transactionDescription>description</transactionDescription>
<transactionType>1</transactionType>
</transaction>";
var serializer = new XmlSerializer(typeof(Transaction));
using(var stream = new StringReader(data))
using(var reader = XmlReader.Create(stream))
{
Console.Write(serializer.Deserialize(reader));
}
Also there was a typo in the ending tag for transactionDate
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With