m_kramar
m_kramar

Reputation: 420

deserialize with different root element names

The following example gives me "[One xmlns=''] was not expected." exception

public abstract class BaseClass{ }

[XmlRoot("One")]
public class ChildOne : BaseClass {}

[XmlRoot("Two")]
public class ChildTwo : BaseClass { }

class Program
{
    private static void Main(string[] args)
    {
        var ser = new XmlSerializer(typeof (BaseClass), new Type[] {typeof (ChildOne), typeof (ChildTwo)});
        var obj1 = ser.Deserialize(new StringReader(@"<?xml version=""1.0""?><One></One>"));
        var obj2 = ser.Deserialize(new StringReader(@"<?xml version=""1.0""?><Two></Two>"));
    }
}

I need to deserialize XML (generated not by me). Root tag may have different names which I have to map to different classes.

PS. I know there is a lot of questions like this around. I have studied them but my problem is still not solved.

Upvotes: 5

Views: 3296

Answers (2)

sa_ddam213
sa_ddam213

Reputation: 43596

To expand on your answer you could use a little LinqToXml to parse the xml to get the root name.

private T Deserialize<T>(string xml, Type[] knownTypes)
{
    var rootType = knownTypes.FirstOrDefault(t => t.GetCustomAttributes<XmlRootAttribute>()
                                                   .Any(a => a.ElementName == XElement.Parse(xml).Name.LocalName));

    return (T)new XmlSerializer(rootType ?? typeof(T), knownTypes).Deserialize(new StringReader(xml));
}

Upvotes: 1

m_kramar
m_kramar

Reputation: 420

No hype building up around my question. Community might be thinking it is just another stupid question asked by an idiot. They might be right. I'll have to answer it myself but beware: the answer might be stupid too.

I ended up probing root element of XML, then mapping it to one of the known types and deserializing using that type. Like so:

public abstract class BaseClass{ }

[XmlRoot("One")]
public class ChildOne : BaseClass {}

[XmlRoot("Two")]
public class ChildTwo : BaseClass { }

class Program
{
    private static void Main(string[] args)
    {
        var known = new Type[] {typeof (ChildOne), typeof (ChildTwo)};
        var obj1 = Deserialize<BaseClass>(@"<?xml version=""1.0""?><One></One>", known);
        var obj2 = Deserialize<BaseClass>(@"<?xml version=""1.0""?><Two></Two>", known);
    }

    private static T Deserialize<T>(string xml, Type[] knownTypes)
    {
        Type rootType = typeof (T);

        if (knownTypes.Any())
        {
            using (var reader = XmlReader.Create(new StringReader(xml)))
            {
                reader.MoveToContent();

                rootType = (from kt in knownTypes
                        let xmlRoot = kt.GetCustomAttributes<XmlRootAttribute>().FirstOrDefault()
                        where kt.Name == reader.Name || (xmlRoot != null && xmlRoot.ElementName == reader.Name)
                        select kt).FirstOrDefault() ?? typeof(T);
            }
        }

        return (T) new XmlSerializer(rootType, knownTypes).Deserialize(new StringReader(xml));
    }
}

Upvotes: 3

Related Questions