XML Deserializing lists with objects only getting one level

1.2k Views Asked by At

This is similar to many questions I've looked at on here, but none of them have helped or fit my situation exactly. I'm trying to deserialize XML output from SQL Server into C# objects.

The classes I have are comprised of some properties and a list of other objects. The problem is that when it deserializes, it only grabs the first item of each list.

Here's my code:

The XML:

<Product>
  <Id>2</Id>
  <Name>Foo</Name>
  <Versions>
    <Version>
      <Id>2</Id>
      <Product>Foo</Product>
      <VersionNumber>2.0</VersionNumber>
      <Resources>
        <Resource>
          <Id>5</Id>
          <Name>FunTimes</Name>
          <Uri>/fun</Uri>
          <Properties>
            <Property>
              <Id>25</Id>
              <Name>Time</Name>
              <PropertyTypeId>5</PropertyTypeId>
              <EnumerationId>7</EnumerationId>
              <Enumeration>
                <Id>7</Id>
                <Name>Time</Name>
                <Members>
                  <Member>
                    <Name>Hours</Name>
                  </Member>
                  <Member>
                    <Name>Seconds</Name>
                  </Member>
                </Members>
              </Enumeration>
            </Property>
            <Property>
              <Id>58</Id>
              <Name>Place</Name>
              <PropertyTypeId>4</PropertyTypeId>
            </Property>
          </Properties>
        </Resource>
        <Resource>
          <Id>4</Id>
          <Name>BadTimes</Name>
          <Uri>/bad</Uri>
          <Properties>
            <Property>
              <Id>25</Id>
              <Name>Cause</Name>
              <PropertyTypeId>5</PropertyTypeId>
              <EnumerationId>7</EnumerationId>
              <Enumeration>
                <Id>7</Id>
                <Name>Cause</Name>
                <Members>
                  <Member>
                    <Name>Local</Name>
                  </Member>
                  <Member>
                    <Name>International</Name>
                  </Member>
                </Members>
              </Enumeration>
            </Property>
          </Properties>
        </Resource>
      </Resources>
    </Version>
  </Versions>
</Product>

The code I'm using to deserialize:

XmlSerializer deserializer = new XmlSerializer(typeof(Product));
TextReader stringReader = new StringReader(content.ToString());
object obj = deserializer.Deserialize(stringReader);
Product XmlData = (Product) obj;
stringReader.Close();

where the XML is being stored in a StringBuilder called "content".

And here are the classes:

[Serializable]
public class Product
{
    // Fields...

    // Properties    
    [XmlElement]
    public int Id { get; set; }

    [XmlElement]
    public string Name { get; set; }

    [XmlElement]
    public string Comments { get; set; }

    [XmlArray("Versions")]
    [XmlArrayItem("Version")]
    public List<Version> Versions { get; set; }

    // Constructors and methods...
}

[Serializable]
public class Version
{
    // Fields...        

    // Properties
    [XmlElement]
    public int Id { get; set; }

    [XmlElement]
    public string Product { get; set; }

    [XmlElement]
    public string VersionNumber { get; set; }

    [XmlElement]
    public string Comments { get; set; }

    [XmlArray("Resources")]
    [XmlArrayItem("Resource")]
    public List<Resource> Resources { get; set; }

    // Constructors and methods...
}

[Serializable]
public class Resource
{
    // Fields...        

    // Properties
    [XmlElement]
    public int Id { get; set; }

    [XmlElement]
    public string Name { get; set; }

    [XmlElement]
    public string Uri { get; set; }

    [XmlElement]
    public string Comments { get; set; }

    [XmlArray("Properties")]
    [XmlArrayItem("Property")]
    public List<Property> Properties { get; set; }

    // Constructors and methods...
}

[Serializable]
public class Property
{
    // Fields...

    // Properties
    [XmlElement]
    public int Id { get; set; }

    [XmlElement]
    public string Name { get; set; }

    [XmlElement]
    public PropertyType PropertyTypeId { get; set; }

    [XmlElement]
    public int? MaximumStringLength { get; set; }

    [XmlElement]
    public double? MinimumValue { get; set; }

    [XmlElement]
    public double? MaximumValue { get; set; }

    [XmlElement]
    public int? EnumerationId { get; set; }

    [XmlElement]
    public PropertyEnumeration Enumeration { get; set; }

    [XmlElement]
    public int? ResourceId { get; set; }

    [XmlElement]
    public string Comments { get; set; }

    [XmlArray("Properties")]
    [XmlArrayItem("Property")]
    public List<Property> CompositeProperties { get; set; }

    // Constructors and methods...
}

And here's the result that it gives me if I re-serialize it as XML. (I know for a fact that it isn't the re-serialization's fault.)

<?xml version="1.0" encoding="utf-16"?>
<Product xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Id>2</Id>
  <Name>Foo</Name>
  <Versions>
    <Version>
      <Id>2</Id>
      <Product>Foo</Product>
      <VersionNumber>2.0</VersionNumber>
      <Resources>
        <Resource>
          <Id>5</Id>
          <Name>FunTimes</Name>
          <Uri>/fun</Uri>
          <Properties>
            <Property>
              <Id>25</Id>
              <Name>Time</Name>
              <PropertyTypeId>5</PropertyTypeId>
              <MaximumStringLength xsi:nil="true" />
              <MinimumValue xsi:nil="true" />
              <MaximumValue xsi:nil="true" />
              <EnumerationId>7</EnumerationId>
              <Enumeration>
                <Id>7</Id>
                <Members>
                  <Member>Hours</Member>
                </Members>
              </Enumeration>
              <ResourceId xsi:nil="true" />
            </Property>
          </Properties>
        </Resource>
      </Resources>
    </Version>
  </Versions>
</Product>

There's also an Enumeration class and some other helper classes, but they're not important. Basically I need it to give me the rest of the items in the XML. I've tried having the list properties use the XmlElement tag, but that produces the same result. How can I make it read all of the items in the XML?

Edit: Oleg mentioned in a comment that it worked for him. Does anyone know if there's a way that my system in particular would be messing it up?

Edit: Found the solution. I unfortunately hadn't even given you all enough information to solve it. In the XML, it says

<Members>
  <Member>
    <Name>Local</Name>
  </Member>
  <Member>
    <Name>International</Name>
  </Member>
</Members>

under Enumeration. In my Enumeration class, I had a property that was a list of strings called Members. It was expecting a list of Members with a Name property inside, so it freaked out. By changing it to

<Members>
  <Member>Local</Member>
  <Member>International</Member>
</Members>

it fixed the issue.

1

There are 1 best solutions below

4
On

Try this. I used a file so I replaced the text reader. You don't need two levels of items like Properties and Property. One level can be eliminated if you change the XML

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XmlSerializer xs = new XmlSerializer(typeof(Product));
            XmlTextReader reader = new XmlTextReader(FILENAME);
            Product XML = (Product)xs.Deserialize(reader);
        }
    }
    [XmlRoot("Product")]
    public class Product
    {
        // Fields...

        // Properties    
        [XmlElement("Id")]
        public int Id { get; set; }

        [XmlElement("Name")]
        public string Name { get; set; }

        private string Comments { get; set; }

        [XmlElement("Versions")]
        public Versions Versions { get; set; }

        // Constructors and methods...
    }
    [XmlRoot("Versions")]
    public class Versions
    {
        [XmlElement("Version")]
        public List<Version> Version { get; set; }
    }

    [XmlRoot("Version")]
    public class Version
    {
        // Fields...        

        // Properties
        [XmlElement("Id")]
        public int Id { get; set; }

        [XmlElement("Product")]
        public string Product { get; set; }

        [XmlElement("VersionNumber")]
        public string VersionNumber { get; set; }

        [XmlElement("Comments")]
        public string Comments { get; set; }

        [XmlElement("Resources")]
        public Resources Resources { get; set; }

        // Constructors and methods...
    }

    [XmlRoot("Resourses")]
    public class Resources
    {
        [XmlElement("Resource")]
        public List<Resource> Resource { get; set; }
    }
    [XmlRoot("Resourse")]
    public class Resource
    {
        // Fields...        

        // Properties
        [XmlElement("Id")]
        public int Id { get; set; }

        [XmlElement("Name")]
        public string Name { get; set; }

        [XmlElement("Uri")]
        public string Uri { get; set; }

        private string Comments { get; set; }

        [XmlElement("Properties")]
        public Properties Properties { get; set; }
    }
        // Constructors and methods.
    [XmlRoot("Properties")]
    public class Properties
    {
        [XmlElement("Property")]
        public List<Property> properties { get; set; }
    }
    [XmlRoot("Property")]
    public class Property
    {
        // Fields...

        // Properties
        [XmlElement("Id")]
        public int Id { get; set; }

        [XmlElement("Name")]
        public string Name { get; set; }

        [XmlElement("PropertyTypeId")]
        public string PropertyTypeId { get; set; }

        private int? MaximumStringLength { get; set; }

        private double? MinimumValue { get; set; }

        private double? MaximumValue { get; set; }

        [XmlElement("EnumerationId")]
        public int? EnumerationId { get; set; }

        private int? ResourceId { get; set; }

        private string Comments { get; set; }

        [XmlElement("Enumeration")]
        public Enumeration Enumeration { get; set; }

        // Constructors and methods...
    }
    [XmlRoot("Enumeration")]
    public class Enumeration
    {
        [XmlElement("Id")]
        public int Id { get; set; }

        [XmlElement("Name")]
        public string Name { get; set; }

        [XmlElement("Members")]
        public Members Members { get; set; }
    }
    [XmlRoot("Members")]
    public class Members
    {
        [XmlElement("Member")]
        public List<Member> Member { get; set; }
    }
    [XmlRoot("Member")]
    public class Member
    {
        [XmlElement("Name")]
        public string Name { get; set; }
    }
}
​