Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserialize empty XML element as Guid.Empty

I have some troubles with deserializing.

<Order>
    ...
    <CardNumber />
    ...
</Order>

If I use

<CardNumber>00000000-0000-0000-0000-000000000000</CardNumber>

it's working normally, but in case when I use just <CardNumber /> - object is not deserializing (

Is there any way to deserialize empty element as Guid.Empty?

Property which should be mapped with value of this element:

[XmlElement(ElementName = "CardNumber")]
[JsonProperty("CardNumber")]
public Guid? CardNumber { get; set; }

Same situation in JSON works normally and use Guid.Empty instead of empty element value

{
    "CardNumber": ""
}
like image 713
ashpakov Avatar asked Jul 28 '16 09:07

ashpakov


People also ask

What is wrong with my deserialization?

The only thing that is wrong is your input string for deserialization. if the corresponding element is missing in the XML. "Missing" is very different to "empty"; your B is empty, not missing. initialisers and the default ctor. Then it applies all the *found* items, else applies the [DefaultValue] (if one) to any that were omitted. If it

What happens if an element is missing from an XML file?

if the corresponding element is missing in the XML. "Missing" is very different to "empty"; your B is empty, not missing. initialisers and the default ctor. Then it applies all the *found* items, else applies the [DefaultValue] (if one) to any that were omitted. If it isn't in the xml it isn't set, so it would remain null. I guess your *real*

What is system XML XML element?

System. Xml Xml Element. Is Empty Property System. Xml Gets or sets the tag format of the element. true if the element is to be serialized in the short tag format "<item/>"; false for the long format "<item></item>".


2 Answers

The exception you are seeing explains the problem clearly:

System.InvalidOperationException occurred
  Message="There is an error in XML document (3, 3)."
  InnerException: System.FormatException
       Message="Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)."

As stated, XmlSerializer does not support deserializing an empty string to a Guid. Thus you will need to do the conversion manually using a surrogate property:

[XmlRoot("Order")]
public class Order
{
    [XmlIgnore]
    [JsonProperty("CardNumber")]
    public Guid? CardNumber { get; set; }

    [XmlElement(ElementName = "CardNumber", IsNullable = true)]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
    [JsonIgnore]
    public string XmlCardNumber
    {
        get
        {
            if (CardNumber == null)
                return null;
            else if (CardNumber.Value == Guid.Empty)
                return "";
            return XmlConvert.ToString(CardNumber.Value);
        }
        set
        {
            if (value == null)
                CardNumber = null;
            else if (string.IsNullOrEmpty(value))
                CardNumber = Guid.Empty;
            else
                CardNumber = XmlConvert.ToGuid(value);
        }
    }
}

If this is something you need to do in many different types that have Guid? properties, you can extract a surrogate type like so:

[XmlType(AnonymousType = true, IncludeInSchema = false)]
public class XmlGuid
{
    [XmlIgnore]
    public Guid Guid { get; set; }

    [XmlText]
    public string XmlCardNumber
    {
        get
        {
            if (Guid == Guid.Empty)
                return null;
            return XmlConvert.ToString(Guid);
        }
        set
        {
            if (string.IsNullOrEmpty(value))
                Guid = Guid.Empty;
            else
                Guid = XmlConvert.ToGuid(value);
        }
    }

    public static implicit operator Guid?(XmlGuid x)
    {
        if (x == null)
            return null;
        return x.Guid;

    }

    public static implicit operator XmlGuid(Guid? g)
    {
        if (g == null)
            return null;
        return new XmlGuid { Guid = g.Value };
    }

    public static implicit operator Guid(XmlGuid x)
    {
        if (x == null)
            return Guid.Empty;
        return x.Guid;

    }

    public static implicit operator XmlGuid(Guid g)
    {
        return new XmlGuid { Guid = g };
    }
}

And use it like:

[XmlRoot("Order")]
public class Order
{
    [XmlElement(Type = typeof(XmlGuid), ElementName = "CardNumber", IsNullable = true)]
    [JsonProperty("CardNumber")]
    public Guid? CardNumber { get; set; }
}

Here I am taking advantage of the fact that the XmlElementAttribute.Type property automatically picks up the implicit conversion I defined for Guid? from and to XmlGuid.

like image 155
dbc Avatar answered Sep 19 '22 20:09

dbc


Null is not the same as Guid.Empty. In the JSON serializer, you denote null using an empty string.

If you serialize your class using XmlSerializer you'll see it uses xsi:nil="true" to denote a null value.

For example:

<Order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <CardNumber xsi:nil="true" />
</Order>
like image 38
Eli Arbel Avatar answered Sep 20 '22 20:09

Eli Arbel