locked
Serialization of List<> where elements are using simple inheritance structure RRS feed

  • Question

  • Hi,

    I've got the following classes:

    [XmlRoot("pageClass")]
        public class PageClass
        {
            [XmlAttribute("Id")]
            public Guid ID { get; set; }
            [XmlArray("questionClasses")]
            //[XmlArrayItem("questionClass")]
            public List<QuestionClass> QuestionClasses { get; set; }
    
            public PageClass()
            {
                this.QuestionClasses = new List<QuestionClass>();
            }
    
        }
    
    
    
    
    [XmlRoot("questionClass")]
        [XmlInclude(typeof(DichotomousQuestionClass))]
       [XmlInclude(typeof(MultipleChoiceSingleAnwserQuestionClass))]
     [XmlInclude(typeof(MultipleChoiceMultipleAnwserQuestionClass))]
        [XmlInclude(typeof(ScaleQuestionClass))]
        [XmlInclude(typeof(DifferentialScaleQuestionClass))]
        [XmlInclude(typeof(TextQuestionClass))]
        [XmlInclude(typeof(MultipleTextQuestionClass))]
        public class QuestionClass
        {
            [XmlAttribute("Id")]
            public Guid ID { get; set; }
            [XmlAttribute("questionText")]
            public string QuestionText { get; set; }
            //[XmlElement("optionClasses")]
            [XmlArray("optionClasses")]
            [XmlArrayItem("optionClass")]
            public List<OptionClass> OptionClasses { get; set; }
    
            public QuestionClass()
            {
                this.OptionClasses = new List<OptionClass>();
            }
    
        }
    
    
    
    
    And classes that inherit from QuestionClasses, namely, DichotomousQuestionClass, MultipleChoiceSingleAnwserQuestionClass, MultipleChoiceMultipleAnwserQuestionClass, ScaleQuestionClass etc.

    Now what my problem is is that when I try to serialize PageClass which contains a collection of classes defined above I got always in my result element like <questionClass type="x">.
    Instead I would like in my xml to have element names based on the actual class names.
    So it would look like:
    <pageClass>
      <questionClasses>
         <dichotomousQuestionClass/>
         <scaleQuestionClass/>
          ...
      </questionClasses>
    </pageClass>


    I would be grateful for any suggestions.
    Thanks.
    Sunday, June 21, 2009 12:50 AM

Answers

  • Say that we've got one class which holds a list of objects. Objects in that list may use some inheritance model. For instance, classes Vehicle, Car and Motorbike.

    public class Vehicle
    {
    }

    public class Car : Vehicle
    {
    }

    public class Motorbike : Vehicle
    {
    }

    Now we've got a class called Offer which contains a list of offered Vehicles:

    public class Offer
    {
    public List<Vehicles> OfferedVehicles { get; set; }
    }


    And we want to serialize it in such a way that xml looks as follows:

    <Offer>
    <Motorbike/>
    <Car/>
    <Motorbike/>
    </Offer>

    instead:

    <Offer>
    <Vehicle xsi:type="Motorbike"/>
    <Vehicle xsi:type="Car" />
    <Vehicle xsi:type="Motorbike />
    </Offer>

    All we need to do is to mark a collection with XmlArrayItemAttribute like :

    public class Offer
    {
    [XmlArrayItemAttribute("Motorbike", typeof(Motorbike))]
    [XmlArrayItemAttribute("Car", typeof(Car))]
    public List<Vehicles> OfferedVehicles { get; set; }
    }

    Additionally, we have to let the serializer know that several classes inherit from our Vehicle, this can be done by the use of XmlInclude attribute:

    [XmlInclude(typeof(Car))]
    [XmlInclude(typeof(Motorbike)]
    public class Vehicle
    {
    }

    That's it.
    Does it make sense? Btw. sorry for my English.

    Tuesday, June 23, 2009 12:53 PM

All replies

  • I don't know the answer off the top of my head. However, I recommend you research this from the XML direction. See if you can create an XML schema that can validate your sample XML. Be sure to include some attributes or other content unique to the "derived" classes.

    Once you have such a schema, run it through XSD.EXE to see what class structure it creates. You could either use that structure, or else use it as a hint as to how you could change your structure to fit.

    John Saunders
    WCF is Web Services. They are not two separate things.
    Use WCF for All New Web Service Development, instead of old ASMX or obsolete WSE
    Use File->New Project to create Web Service Projects
    Monday, June 22, 2009 3:02 PM
    Moderator
  • Thanks, it worked!
    Monday, June 22, 2009 3:19 PM
  • I'm glad.

    What worked? Could you post the solution so others who read this in the future will know what worked?
    John Saunders
    WCF is Web Services. They are not two separate things.
    Use WCF for All New Web Service Development, instead of old ASMX or obsolete WSE
    Use File->New Project to create Web Service Projects
    Monday, June 22, 2009 3:22 PM
    Moderator
  • I had the schema generated already from other tool, so when I passed it to xsd.exe it generated c# classes as I needed.
    The generated classes are not exactly the same as I wanted - especially collections - xsd.exe generated collections as a seperate classes with arrays of objects.
    But as far as it works it is fine for me.

    Thanks again.
    Monday, June 22, 2009 10:17 PM
  • Ok. I found a better way of doing that. A collection of objects with inheritance model can be marked with attribute [XmlArrayItemAttribute(allowedType)].
    Monday, June 22, 2009 11:57 PM
  • If you wouldn't mind, it would be very helpful if you could post an example of the solution. That way, people finding this thread later will not only know that you found a solution, they'll know what the solution is.

    Otherwise, believe me, there will be a string of replies to this thread saying, "what was the solution?".

    John Saunders
    WCF is Web Services. They are not two separate things.
    Use WCF for All New Web Service Development, instead of old ASMX or obsolete WSE
    Use File->New Project to create Web Service Projects
    Tuesday, June 23, 2009 12:47 AM
    Moderator
  • Say that we've got one class which holds a list of objects. Objects in that list may use some inheritance model. For instance, classes Vehicle, Car and Motorbike.

    public class Vehicle
    {
    }

    public class Car : Vehicle
    {
    }

    public class Motorbike : Vehicle
    {
    }

    Now we've got a class called Offer which contains a list of offered Vehicles:

    public class Offer
    {
    public List<Vehicles> OfferedVehicles { get; set; }
    }


    And we want to serialize it in such a way that xml looks as follows:

    <Offer>
    <Motorbike/>
    <Car/>
    <Motorbike/>
    </Offer>

    instead:

    <Offer>
    <Vehicle xsi:type="Motorbike"/>
    <Vehicle xsi:type="Car" />
    <Vehicle xsi:type="Motorbike />
    </Offer>

    All we need to do is to mark a collection with XmlArrayItemAttribute like :

    public class Offer
    {
    [XmlArrayItemAttribute("Motorbike", typeof(Motorbike))]
    [XmlArrayItemAttribute("Car", typeof(Car))]
    public List<Vehicles> OfferedVehicles { get; set; }
    }

    Additionally, we have to let the serializer know that several classes inherit from our Vehicle, this can be done by the use of XmlInclude attribute:

    [XmlInclude(typeof(Car))]
    [XmlInclude(typeof(Motorbike)]
    public class Vehicle
    {
    }

    That's it.
    Does it make sense? Btw. sorry for my English.

    Tuesday, June 23, 2009 12:53 PM
  • That's excellent, thanks.

    John Saunders
    WCF is Web Services. They are not two separate things.
    Use WCF for All New Web Service Development, instead of old ASMX or obsolete WSE
    Use File->New Project to create Web Service Projects
    Tuesday, June 23, 2009 3:59 PM
    Moderator