views:

283

answers:

2

I want to serialize the following Xml structure:

  <XmlRootElement>
     <Company name="Acme Widgets LLC">
        <DbApplication name="ApplicationA" vendor="oracle">
           <ConnSpec environment="DEV" 
                     server="DBOraDev1201" 
                     database="AppA" 
                     userId="MyUser" 
                     password="5613456#6%^%$%$#" />
           <ConnSpec environment="QA" 
                     server="DBOraQA1205" 
                     database="AppA" 
                     userId="MyUser" 
                     password="5613456#6%^%$%$#" />
       </DbApplication>
       <DbApplication name="AnotherApp" "vendor="SQLServer">
           <ConnSpec environment="DEV" 
                     server="DBMsSqlDev1201" 
                     catalog="AnoptherApp" 
                     userId="MyUser" 
                     password="5613456#6%^%$%$#" />
           <ConnSpec environment="QA" 
                     server="DBMsSqlQA1565" 
                     catalog="AnotherApp" 
                     userId="MyUser" 
                     password="5613456#6%^%$%$#" />
       </DbApplication>
     </Company>
     <Company name = "ExpertSoftware Inc" ....
        ...
     </Company>
  </XmlRootElement>

but I have discovered in link text

Quote from above link: ...

  • Q: Why aren't all properties of collection classes serialized?
  • A: The XmlSerializer only serializes the elements in the collection when it detects either the IEnumerable or the ICollection interface. This behavior is by design. The only work around is to re-factor the custom collection into two classes, one of which exposes the properties including one of the pure collection types.

...

after discovering that you can't serialize or deserialize a collection that has other Xml attributes in it... The suggested workaround is to separate the element that has the collection from the the ones that have other attributes... i.e, You have to change the structure so that it looks like this instead:

  <XmlRootElement>
     <Companys>
        <Company name="Acme Widgets LLC">
           <DbApplications>
               <DbApplication name="ApplicationA" vendor="oracle">
                  <ConnSpecs>
                     <ConnSpec environment="DEV" 
                         server="DBOraDev1201" ...  />
                     <ConnSpec environment="QA" 
                         server="DBOraQA1205" 
                         database="AppA" ... />
                  </ConnSpecs>
               </DbApplication>
               <DbApplication name="AnotherApp" "vendor="SQLServer">
                  <ConnSpecs>
                      <ConnSpec environment="DEV" ... />
                      <ConnSpec environment="QA"  ... />
                  </ConnSpecs>
                </DbApplication>
           </DbApplications>
         </Company>
         <Company name = "ExpertSoftware Inc" ....
             ...
         </Company>
     </Companys>
  </XmlRootElement>

Does anyone know why this is so? or if there is some other way to do this?

+1  A: 

If you are using XmlSerializer you need to indicate it how to serialize your collections:

public class XmlRootElement
{
    [XmlElement(ElementName="Company")]
    public Company[] Company { get; set; }

    // Other properties ....
}

public class Company
{
    [XmlAttribute(AttributeName="name")]
    public string Name { get; set; }

    [XmlElement(ElementName = "DbApplication")]
    public DbApplication[] DbApplication { get; set; }

    // Other properties ....
}

public class DbApplication
{
    [XmlElement(ElementName = "ConnSpec")]
    public ConnSpec[] ConnSpec { get; set; }

    // Other properties ....
}

public class ConnSpec
{
    // Other properties ....
}

And then:

using (Stream stream = new FileStream("test.xml", FileMode.Open, FileAccess.Read, FileShare.Read))
{
    XmlSerializer serializer = new XmlSerializer(typeof(XmlRootElement));
    XmlRootElement root = (XmlRootElement)serializer.Deserialize(stream);
}

Hope this helps.

Darin Dimitrov
For other elements (not collection elements) you only have to do this if the element name is different from the class name... But I will try this...
Charles Bretana
+1  A: 

An alternative to adding XMl serialization attributes to all of your classes is to implement the IXmlSerializable interface on the root element container class. The ReadXml and WriteXml methods of this interface will be used by the XmlSerializer, allowing you to have more fine grained control over the serialization/deserialization process.

Oppositional