Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to serialize a custom struct as an xml attribute?

Is is possible to serialize a custom struct as an xml attribute?

Sample code:

public class Dummy<T>
{
    private Dummy() { }
    public Dummy(T item1)
    {
        Item1 = item1;
        Item2 = item1;
    }

    public T Item1 { get; set; }
    [XmlAttribute]
    public T Item2 { get; set; }
}

public struct Meh
{
    public int Prop { get; set; }
}

[Test]
public void XmlMehTest()
{
    var meh = new Meh{Prop = 1};
    var dummy = new Dummy<Meh>(meh);
    using (var writer = new StringWriter())
    {
        var serializer = new XmlSerializer(dummy.GetType());
        // System.InvalidOperationException : Cannot serialize member 'Meh2' of type Meh. 
        // XmlAttribute/XmlText cannot be used to encode complex types.
        serializer.Serialize(writer, dummy);
        Console.Write(writer.ToString());
    }
}

[Test]
public void XmlDateTimeTest()
{
    var dummy = new Dummy<DateTime>(DateTime.Now);
    using (var writer = new StringWriter())
    {
        var serializer = new XmlSerializer(dummy.GetType());
        serializer.Serialize(writer, dummy);
        Console.Write(writer.ToString());
    }
}

Please ignore that the struct is mutable, wrote it like that for a compact sample.

This is truly a first-world-developer-problem but I'm still curious :)

like image 726
Johan Larsson Avatar asked Oct 01 '22 23:10

Johan Larsson


1 Answers

The documentation says:

You can assign the XmlAttributeAttribute only to public fields or public properties that return a value (or array of values) that can be mapped to one of the XML Schema definition language (XSD) simple types (including all built-in datatypes derived from the XSD anySimpleType type). The possible types include any that can be mapped to the XSD simple types, including Guid, Char, and enumerations.

So to do this, we should be able to create our own type definition for XSD,I guess we can do that.Because this documentation contains full explanation about it.But what we can't do is, we can't include our definition to this list.Initially XML Serializer uses these types to figure out your type's XSD type definition.You can use this attribute with DateTime because it's definition creating with this method and storing in a HashTable:

AddPrimitive(typeof(DateTime), "dateTime", "DateTime", 
             TypeFlags.XmlEncodingNotRequired | 
             TypeFlags.HasCustomFormatter | 
             TypeFlags.CanBeElementValue | **TypeFlags.CanBeAttributeValue**);

AddPrimitive method:

private static void AddPrimitive(Type type, string dataTypeName, string formatterName, TypeFlags flags)
    {
        XmlSchemaSimpleType dataType = new XmlSchemaSimpleType {
            Name = dataTypeName
        };
        TypeDesc desc = new TypeDesc(type, true, dataType, formatterName, flags);
        if (primitiveTypes[type] == null)
        {
            primitiveTypes.Add(type, desc);
        }
        primitiveDataTypes.Add(dataType, desc);
        primitiveNames.Add(dataTypeName, "http://www.w3.org/2001/XMLSchema", desc);
    }

And this definition calling from XmlReflectionImporter like this (which is generating the exception according to StackTrace):

this.GetTypeDesc(name, ns, TypeFlags.CanBeElementValue | TypeFlags.CanBeTextValue | TypeFlags.CanBeAttributeValue);

I guess most important thing is here TypeFlags.CanBeAttributeValue and I think it's specify that this type can be attibute value.So as a result maybe we can serialize custom structs as an XmlAttirube but we can't do it with standart XmlSerializer.Because as I said it's using this list to figure out XSD type definition.And it's an initial list and it's impossible to add new element to that list.

P.S. You might want take a look at here http://msdn.microsoft.com/en-us/library/8w07bk3h(v=vs.80).aspx

like image 168
Selman Genç Avatar answered Oct 20 '22 07:10

Selman Genç