0

I am using C# 9.0, and using XmlSerializer to deserialize an xml.

my code

public class MyObject 
{
    [XmlElement]
    public decimal? MyMoney {get; set;}
    [XmlElement]
    public string Name {get; set;}
}

and the xml deserialize code

var xmlSerializer = new XmlSerializer(typeof(MyObject));
var myobj = (MyObject) xmlSerializer (new StringReader(myInputString));

The xml contains a number with thousand group separator

How to customize the deserialization to override it, so it can be reusable in different locations

<MyObject>
<MyMoney> 222,333.55</MyMoney>
<Name> anything </Name>
</MyObject>
Ghassan Karwchan
  • 3,355
  • 7
  • 37
  • 65
  • `XmlSerializer` does not support using a comma (or any other character) for a [number group separator](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.numberformatinfo.numbergroupseparator). You may need to use a surrogate string-valued property as shown in e.g. [XML-Deserialization of double value with German decimal separator in C#](https://stackoverflow.com/q/8463733). Preprocessing with XSLT is another option, see [XmlSerializer to deserialize decimal with comma(,) decimal symbol](https://stackoverflow.com/q/6116354). – dbc Aug 22 '22 at 22:46
  • Appreciate your answer. I updated by question to see how we can do it in re-usable way, so I can use it on many different elements. – Ghassan Karwchan Aug 22 '22 at 23:32
  • 222,333.444 *is not* reusable in different locations as it is region-specific format. It is bad idea to put such format into an XML that generally designed to be consumed world-wide. You really should fix the source of that behavior. Alternatively declare your custom `UmbigiousNumber` type and implement custom serialization for it - i.e. https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.ixmlserializable?view=net-6.0 – Alexei Levenkov Aug 23 '22 at 00:36

2 Answers2

0

You can get this value in string type and remove unsupported characters then convert it.

  public class MyObject
    {

        [XmlElement]
        public string MyMoney { get; set; }


        [XmlElement]
        public decimal? Money
        {
            get
            {
                decimal _v = 0;
                if (!string.IsNullOrEmpty(MyMoney))
                {
                    decimal.TryParse(MyMoney.Replace(",", ""), out _v);
                }
                return _v;
            }
        }
        [XmlElement]
        public string Name { get; set; }
    }
0

There are many ways to solve this problem.
I think the simplest one will be the following.

Set the XmlIgnore attribute on the MyMoney property.

public class MyObject
{
    [XmlIgnore]
    public decimal? MyMoney { get; set; }
    [XmlElement]
    public string Name { get; set; }
}

Add an UnknownElement event handler to the serializer.

void XmlSerializer_UnknownElement(object? sender, XmlElementEventArgs e)
{
    if (e.Element.Name == nameof(MyObject.MyMoney))
    {
        var money = decimal.Parse(e.Element.InnerText, CultureInfo.InvariantCulture);
        var myobj = (MyObject)e.ObjectBeingDeserialized;
        myobj.MyMoney = money;
    }
}

The serializer will not find the property during operation, so the event will be triggered. In it, we can implement any logic for parsing values.

var xmlSerializer = new XmlSerializer(typeof(MyObject));
xmlSerializer.UnknownElement += XmlSerializer_UnknownElement;

var myobj = (MyObject)xmlSerializer.Deserialize(new StringReader(myInputString));
Console.WriteLine(myobj.Name + " " + myobj.MyMoney);
Alexander Petrov
  • 13,457
  • 2
  • 20
  • 49