user53885
user53885

Reputation: 3829

Trying to deserialize XML to C# object

I have an XML file that represents a serialized instance of what in the UI is a Form. This form is designed by a user, and allows other users to fill out the form. Once the Form is saved, instance data is serialized to a column in the database. I'm calling this instance data, and I need to parse it but am running into issues in deserialization - using C# standard deserialization. This is one Form as far as the user is concerned, but the instance data is actually comprised of "subforms" - these are the forms that the Form the user sees is comprised of.

Here is the format of the XML Document:

 <Thing>
  <TheSections>
    <TheSection>
      <TheForms>
        <TheForm name="SomeUserForm">
          <Property name="BackgroundColor"/>
          <Control name="GroupHeading1" type="header" hasdata="N">
            <Control name="GroupHeading2" type="subheader" hasdata="N">
              <Control name="TextEntry1" type="detail" hasdata="Y">
                <Property name="ValueField">I want to order 3 of these</Property>
                <Property name="Type">TextField</Property>
              </Control>
            </Control>
          </Control>
        </Form>
        <Form>....</Form>
        <Form>....</Form>
        <Form>....</Form>
      </TheForms>
    </TheSection>
    <TheSection>...</TheSection>
  </TheSections>
</Thing>

As you can see, Controls can be nested in other Controls, and Properties are part of a control.

I have deserialization working down to the Form level, however when I try and deserialize the Controls it breaks.

The nested Controls in this file, are not important for me - as I am looking to get one level collection of all Controls, regardless of heirarchy and all of their Properties. I would like to add a property to the Controls which indicates what their Control parent name was if there is one - but other than that I'd like an object that has a flat collection of Controls and their properties.

Is there a way to have the deserialization look at this XML as if the controls are all at the same level, regardless of their hierarchy, and just deserialize all the nesting automatically?

Thank you for any tips!

Here is the XSD generated from the XML file in Visual Studio 2008(as you'll see, the original XML does not have Forms above each Form or Sections above each Section - I'm adding that as I load the XML:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Thing">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="TheSection">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="TheForm">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element maxOccurs="unbounded" name="Control">
                      <xs:complexType mixed="true">
                        <xs:sequence>
                          <xs:element name="Group">
                            <xs:complexType>
                              <xs:sequence minOccurs="0">
                                <xs:element maxOccurs="unbounded" name="GroupItem">
                                  <xs:complexType>
                                    <xs:attribute name="name" type="xs:string" use="required" />
                                    <xs:attribute name="taborder" type="xs:unsignedByte" use="required" />
                                    <xs:attribute name="posneg" type="xs:string" use="required" />
                                    <xs:attribute name="qualifier" type="xs:string" use="required" />
                                  </xs:complexType>
                                </xs:element>
                              </xs:sequence>
                              <xs:attribute name="name" type="xs:string" use="required" />
                              <xs:attribute name="render" type="xs:string" use="required" />
                              <xs:attribute name="size" type="xs:unsignedByte" use="required" />
                              <xs:attribute name="indent" type="xs:string" use="required" />
                              <xs:attribute name="newline" type="xs:string" use="required" />
                            </xs:complexType>
                          </xs:element>
                          <xs:element minOccurs="0" maxOccurs="unbounded" name="Control">
                            <xs:complexType mixed="true">
                              <xs:sequence minOccurs="0">
                                <xs:element maxOccurs="unbounded" name="Property">
                                  <xs:complexType>
                                    <xs:simpleContent>
                                      <xs:extension base="xs:string">
                                        <xs:attribute name="name" type="xs:string" use="required" />
                                      </xs:extension>
                                    </xs:simpleContent>
                                  </xs:complexType>
                                </xs:element>
                              </xs:sequence>
                              <xs:attribute name="name" type="xs:string" use="required" />
                              <xs:attribute name="hasdata" type="xs:string" use="required" />
                              <xs:attribute name="type" type="xs:string" use="required" />
                              <xs:attribute name="font" type="xs:string" use="required" />
                              <xs:attribute name="size" type="xs:unsignedByte" use="required" />
                              <xs:attribute name="indent" type="xs:string" use="required" />
                              <xs:attribute name="bold" type="xs:string" use="required" />
                              <xs:attribute name="bullet" type="xs:string" use="required" />
                              <xs:attribute name="newline" type="xs:string" use="required" />
                              <xs:attribute name="render" type="xs:string" use="required" />
                              <xs:attribute name="forceparagraph" type="xs:string" use="required" />
                              <xs:attribute name="startnewsentence" type="xs:string" use="required" />
                              <xs:attribute name="commadelimited" type="xs:string" use="required" />
                              <xs:attribute name="qualifier" type="xs:string" use="required" />
                            </xs:complexType>
                          </xs:element>
                          <xs:element minOccurs="0" name="RenderText" type="xs:string" />
                        </xs:sequence>
                        <xs:attribute name="name" type="xs:string" use="required" />
                        <xs:attribute name="hasdata" type="xs:string" use="required" />
                        <xs:attribute name="type" type="xs:string" use="required" />
                        <xs:attribute name="font" type="xs:string" use="required" />
                        <xs:attribute name="size" type="xs:unsignedByte" use="required" />
                        <xs:attribute name="indent" type="xs:string" use="required" />
                        <xs:attribute name="bold" type="xs:string" use="required" />
                        <xs:attribute name="bullet" type="xs:string" use="required" />
                        <xs:attribute name="newline" type="xs:string" use="required" />
                        <xs:attribute name="render" type="xs:string" use="required" />
                        <xs:attribute name="forceparagraph" type="xs:string" use="required" />
                        <xs:attribute name="startnewsentence" type="xs:string" use="required" />
                        <xs:attribute name="commadelimited" type="xs:string" use="required" />
                        <xs:attribute name="qualifier" type="xs:string" use="required" />
                        <xs:attribute name="headinglevel" type="xs:unsignedByte" use="required" />
                        <xs:attribute name="normalgroup" type="xs:string" use="required" />
                        <xs:attribute name="renderwithdata" type="xs:string" use="required" />
                        <xs:attribute name="grouptype" type="xs:string" use="required" />
                        <xs:attribute name="label" type="xs:string" use="required" />
                      </xs:complexType>
                    </xs:element>
                  </xs:sequence>
                  <xs:attribute name="id" type="xs:string" use="required" />
                  <xs:attribute name="name" type="xs:string" use="required" />
                  <xs:attribute name="type" type="xs:string" use="required" />
                  <xs:attribute name="font" type="xs:string" use="required" />
                  <xs:attribute name="size" type="xs:unsignedByte" use="required" />
                  <xs:attribute name="indent" type="xs:string" use="required" />
                  <xs:attribute name="bold" type="xs:string" use="required" />
                  <xs:attribute name="bullet" type="xs:string" use="required" />
                  <xs:attribute name="newline" type="xs:string" use="required" />
                  <xs:attribute name="forceparagraph" type="xs:string" use="required" />
                  <xs:attribute name="startnewsentence" type="xs:string" use="required" />
                  <xs:attribute name="commadelimited" type="xs:string" use="required" />
                  <xs:attribute name="qualifier" type="xs:string" use="required" />
                  <xs:attribute name="render" type="xs:string" use="required" />
                  <xs:attribute name="rendercount" type="xs:unsignedByte" use="required" />
                </xs:complexType>
              </xs:element>
            </xs:sequence>
            <xs:attribute name="type" type="xs:string" use="required" />
            <xs:attribute name="id" type="xs:unsignedByte" use="required" />
            <xs:attribute name="name" type="xs:string" use="required" />
            <xs:attribute name="render" type="xs:string" use="required" />
            <xs:attribute name="font" type="xs:string" use="required" />
            <xs:attribute name="size" type="xs:unsignedByte" use="required" />
            <xs:attribute name="indent" type="xs:string" use="required" />
            <xs:attribute name="bold" type="xs:string" use="required" />
            <xs:attribute name="bullet" type="xs:string" use="required" />
            <xs:attribute name="newline" type="xs:string" use="required" />
            <xs:attribute name="forceparagraph" type="xs:string" use="required" />
            <xs:attribute name="rendercount" type="xs:unsignedByte" use="required" />
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Here is an example of the class I am using for deserialization:

[ XmlRoot("Section")
    ]
    public class MySectionData
    {
        private MyFormData[] _Forms = new MyFormData[0];

        [ XmlArray("Forms")
        ]
        [ XmlArrayItem("Form")
        ]
        public MyFormData[] Forms
        {
            set
            {
                this._Forms = value;
            }
            get
            {
                return this._Forms;
            }
        }

        [ XmlAttribute("id")
        ]
        public String Id
        {
            set;
            get;
        }
        [XmlAttribute("name")
     ]
        public String name
        {
            set;
            get;
        }

    }

Upvotes: 2

Views: 995

Answers (2)

Josh M.
Josh M.

Reputation: 27821

Have you tried using xsd.exe to generate classes based off of your schema? If the "controls" end up being nested you could still write a function to "flatten" them and return the entire set, right?

It is located here: C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\

Upvotes: 0

Robert Rossney
Robert Rossney

Reputation: 96860

You could spend a lot of time and energy figuring out the nuances of XML serialization and trying to build classes so that they can more or less work with this format. I think, though, that this is easier:

  1. Create a Control class that is serializable into XML. Create a serializable class that has a collection of Control objects, populate it, and serialize it. Now you know what kind of input the XML deserializer wants for this class.

  2. Write an XSLT transform that transforms the input XML you have into the input XML you need.

Upvotes: 2

Related Questions