3

I am currently trying to deserialize an XML using the [Serializable()] command object and I am having some issue. Here is the code sample :

using System;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.IO;

namespace XmlManipulation
{
    public class XmlManip
    {
        public static TestCasesList SerializeTest() //test function
        {
            TestCasesList testslist = null;
            string path = @"C:\Users\sxtx2987\Documents\Visual Studio 2015\Projects\FDB\deleteme\test.xml";

            XmlSerializer serializer = new XmlSerializer(typeof(TestCasesList));

            StreamReader reader = new StreamReader(path);

        testslist = (TestCasesList)serializer.Deserialize(reader);
        reader.Close();
        return testslist;
        }
    }


    [Serializable()]
    public class TestCase
    {
        [System.Xml.Serialization.XmlElement("name")]
        public string name;

        [System.Xml.Serialization.XmlElement("objective")]
        public string objective;

        [System.Xml.Serialization.XmlElement("criteria")]
        public string criteria;

        [System.Xml.Serialization.XmlElement("issue")]
        public string issue;

        [System.Xml.Serialization.XmlElement("clientcomments")]
        public string clientcomments;

        [System.Xml.Serialization.XmlElement("authoritycomments")]
        public string authoritycomments;
    }

    [Serializable()]
    [XmlType("testcaseslist")]
    public class TestCasesList
    {
        [XmlArray("testcase")]
        public TestCase[] TestCase { get; set; }
    }
}

And here is the file I am trying to deserialize

<xml version="1.00" encoding="UTF-8">
    <campaign>
        <name>Test XML</name>
        <number>XXXXXG04-06-1</number>
        <client>Fictional</client>
        <model>Rocket powered boots</model>
        <authority>Fictional authority</authority>
    </campaign>

    <testcaseslist>
        <testcase>
            <name>TestCase001</name>
            <objective>Objective test 1</objective>
            <criteria>Pass criteria test 1</criteria>
            <issue>Issue Description test 1</issue>
            <clientcomments>Client comments test 1</clientcomments>
            <authoritycomments>Authority comments test 1</authoritycomments>
        </testcase>

        <testcase>
            <name>TestCase002</name>
            <objective>Objective test 2</objective>
            <criteria>Pass criteria test 2</criteria>
            <issue>Issue Description test 2</issue>
            <clientcomments>Client comments test 2</clientcomments>
            <authoritycomments>Authority comments test 2</authoritycomments>
        </testcase>
    </testcaseslist>    
</xml>

What I am trying to achieve is taking all the roots element "testcase" and put each child element (namely : name,objective,criteria,issue,clientcomments,authoritycomments) in an class TestCasesList made of multiple classes TestCase.

So in this example :

TestCasesList

|-> testcase 1

|-> testcase 2

|-> etc....

which contains all the elements of the test case.

The code I have above is what I could gather up to now, but since this is quite a specific action that I am trying to do, I fail to find all the relevant information to solve my problem.

The code does not throw any errors, but when I try to call the function

        TestCasesList test = null;

        test = XmlManipulation.XmlManip.SerializeTest();

I get an empty test object.

I think that my problem is the XmlType and XmlArray section, but after a few hours of research and trials, I still cannot get the information from the XML.

Thank you for your time.

Jeph Gagnon
  • 157
  • 3
  • 13

1 Answers1

1

You have a few problems here.

  1. The root element may not be what you think it is. Your code assumes that <testcaseslist> is the root element. But in reality, the following is the root element:

    <xml version="1.00" encoding="UTF-8">
        <!-- XML Contents -->
    </xml>
    

    That root looks like a standard XML declaration:

    <?xml version="1.0" encoding="UTF-8">
    

    But it's missing the question mark <?xml> at the beginning. So you need to modify your code to deal with that. You can do it by skipping forward to the appropriate element using an XmlReader, or deserializing an appropriate container type.

  2. Inside <testcaseslist> the elements <testcase> are not grouped under a container element. Thus you need to use [XmlElement("testcase")] not [XmlArray("testcase")].

  3. To declare a root element name on a class, you must use [XmlRoot("testcaseslist")] not [XmlType("testcaseslist")].

Thus your TestCasesList should look like:

[XmlRoot("testcaseslist")]
public class TestCasesList
{
    [XmlElement("testcase")]
    public TestCase[] TestCase { get; set; }
}

Then, to skip forward in your XML and deserialize the <testcaseslist> element, use XmlReader.ReadToFollowing():

    public static TestCasesList Deserialize(TextReader reader)
    {
        using (var xmlReader = XmlReader.Create(reader))
        {
            // Skip to the <testcaseslist> element.
            if (!xmlReader.ReadToFollowing("testcaseslist", ""))
                return null;

            var serializer = new XmlSerializer(typeof(TestCasesList));
            return (TestCasesList)serializer.Deserialize(xmlReader);
        }
    }

Where reader is your StreamReader reader = new StreamReader(path);.

Alternatively, using the container type:

[XmlRoot("xml")]
public class XmlRoot
{
    public TestCasesList testcaseslist { get; set; }
}

You could do:

    public static TestCasesList Deserialize(TextReader reader)
    {
        var serializer = new XmlSerializer(typeof(XmlRoot));
        var root = (XmlRoot)serializer.Deserialize(reader);
        return root == null ? null : root.testcaseslist;
    }

Some of the difficulties above could have been avoided by automatically generating your c# classes from your XML, e.g. with http://xmltocsharp.azurewebsites.net/. For more see Generate C# class from XML.

Incidentally, [Serializable] has no effect on XmlSerializer.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • Thank you for your detailed explanations. After messing with the XML, I noticed that when I used that kind of structure for serialization, I could simply use the variable names and went with a structure without the [serializable] tags and simply used public variable for the serialization. Your explanations shed some lights on the mechanism of XML for me though. Thank you. – Jeph Gagnon Apr 11 '16 at 18:29