Serializing abstract classes to XML with derived classes. System.InvalidOperationException < Class xmlns=" /> was not expected

StackOverflow https://stackoverflow.com/questions/20813832

문제

I'm making a hotel app as a school project and I can't seem to get this working. I have an abstract class Arrangementen and 3 derived classes.

FamilieArrangementen : StandaardArrangementen StandaardArrangementen : Arrangementen LuxeArrangementen : Arrangementen

Every time i Deserialize the XML file i get the exception System.InvalidOperationException < StandaardArrangement xmlns=" /> was not expected.

I have searched the web for an answer and I'm guessig it is something with the XmlRoot namespace or the XmlInclude is not working correctly

Any suggestions?

This is my code

abstract class Arrangementen

namespace HotelLib.Overkoepelend.Arrangementen
{
    [Serializable()]
    [XmlInclude(typeof(FamilieArrangement))]
    [XmlInclude(typeof(StandaardArrangement))]
    [XmlInclude(typeof(LuxeArrangement))]
    public abstract class Arrangement: ICloneable
    {
    ...
    }
}

class FamilieArrangement

namespace HotelLib.Overkoepelend.Arrangementen
{
    [Serializable]
    public class FamilieArrangement : StandaardArrangement
    {
    ...
    }
}

class StandaardArrangement

namespace HotelLib.Overkoepelend.Arrangementen
{
    [Serializable]
    public class StandaardArrangement : Arrangement
    {
    ...
    }
}

class LuxeArrangement

namespace HotelLib.Overkoepelend.Arrangementen
{
    [Serializable]
    public class LuxeArrangement : Arrangement
    {
    ...
    }
}

Serialization code

internal void WriteArrangement(Arrangement ar, string path)
{
    using (FileStream bestand = File.Open(path, FileMode.OpenOrCreate))
    {         
        XmlSerializer xmls = new XmlSerializer(ar.GetType());
        xmls.Serialize(bestand, ar);
    }
}

Deserialization code

internal Arrangement ReadArrangement(string path)
{
    if (File.Exists(path))
    {
        using (FileStream bestand = File.Open(path, FileMode.OpenOrCreate))
        {    
            try
            {
                xmls = new XmlSerializer(typeof(Arrangement));
                Arrangement ar = (Arrangement) xmls.Deserialize(bestand);
                bestand.Close();
                return ar;
            }
            catch (Exception er)
            {
                MessageBox.Show("" + er.GetBaseException());
            } 
            bestand.Close();       
        }
    }
    return null;
}

the other attempt (which not worked, but gave another error

internal Arrangement ReadArrangement(string pad)
        {
            if (File.Exists(pad))
            {
                using (FileStream bestand = File.Open(pad, FileMode.OpenOrCreate))
                {    
                    try
                    {
                        xmls = new XmlSerializer(typeof(Arrangement));
                        Arrangement ar = (Arrangement) xmls.Deserialize(bestand);

                        bestand.Close();
                        return ar;
                    }
                    catch (Exception )
                    {
                        try
                        {
                            xmls = new XmlSerializer(typeof(FamilieArrangement));
                            FamilieArrangement ar = (FamilieArrangement)xmls.Deserialize(bestand);

                            bestand.Close();
                            return ar;
                        }
                        catch (Exception)
                        {
                            try
                            {
                                xmls = new XmlSerializer(typeof(StandaardArrangement));
                                StandaardArrangement ar = (StandaardArrangement)xmls.Deserialize(bestand);

                                bestand.Close();
                                return ar;
                            }
                            catch (Exception er)
                            {
                                MessageBox.Show("" + er.GetBaseException());
                            } 
                        } 
                    } 

                    bestand.Close();       
                }
            }

            return null;
        }

the Xml file with a StandaardArrangement

<?xml version="1.0"?>
<StandaardArrangement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <AantalVolw xmlns="HotelLib.Overkoepelend.Arrangementen">2</AantalVolw>
  <Kamer xmlns="HotelLib.Overkoepelend.Arrangementen">
    <MaxAantal>4</MaxAantal>
    <Bezetting>
      <Tijdslot>
        <Aankomst>2013-12-28T10:18:21.4384129+01:00</Aankomst>
        <Vertrek>2013-12-31T10:18:21</Vertrek>
      </Tijdslot>
    </Bezetting>
  </Kamer>
  <KlantId xmlns="HotelLib.Overkoepelend.Arrangementen">d4d72906-7b04-46aa-9986-4f22b232fbd0</KlantId>
  <Tijdslot xmlns="HotelLib.Overkoepelend.Arrangementen">
    <Aankomst>2013-12-28T15:09:10.1152899+01:00</Aankomst>
    <Vertrek>2013-12-30T15:09:10.1152899+01:00</Vertrek>
  </Tijdslot>
  <Type xmlns="HotelLib.Overkoepelend.Arrangementen">standaard</Type>
  <MaaltijdType>halfpension</MaaltijdType>
  <Opties>
    <KamerOpties>kluis</KamerOpties>
    <KamerOpties>wifi</KamerOpties>
  </Opties>
</StandaardArrangement>
도움이 되었습니까?

해결책

I'm seeing that you're using ".GetType" to resolve the specific type when you Serialize, but you force the parent type, Arrangement, to DeSerialize. (as someone else also just posted :) )

That is causing the error. Just like Serializing, you have to have the explicit type available; it isn't going to try every child automatically for Deserialize.

An easy answer is to query the xml string for the name.

Before loading the XmlSerializer, load an XmlDocument.

Grab that root name from XmlDocument.DocumentElement.Name.

Use the static Type.GetType method on the string name for the XmlSerializer type.

http://msdn.microsoft.com/en-us/library/system.xml.xmldocument.documentelement(v=vs.110).aspx

Type.GetType("namespace.a.b.ClassName") returns null

다른 팁

Right, a few things are tricky here. First of all, you are trying to read a specific type from XML (StandaardArrangement) while your XmlSerializer is of its base type Arrangement. That is what is causing the exception you see. The XmlSerializer is expecting to read an Arrangement type, while it encounters a StandaardArrangement.

If you would change your reader to

var xmls = new XmlSerializer(typeof(StandaardArrangement));

then this specific part of XML you posted would be deserialized to your desired object of StandaardArrangement.

I am guessing that is also no solution for you, because you probably have a bunch of Arrangement objects stored in XML, which are mixed in one XML file (I guess?).

What I would suggest is a class that contains a Collection of Arrangement objects which you read from XML.

That would result in something like this... (left out specifics, you'll get the idea)

The container class:

public class Arrangements
{
    [XmlArray("Arrangement")]
    [XmlArrayItem("StandaardArrangement", typeof(StandaardArrangement)]
    [XmlArrayItem("LuxeArrangement", typeof(LuxeArrangement)]
    public List<Arrangement> Arrangements
    {
        ...
    }
}

Again, I left out a lot of specifics, I assume you can fill in the blanks.

HTH!

The XML (left out details just to give an idea, you probably understand what I mean already anyway):

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top