1

First off, I followed the answer given here, but I still can not get the following to work.

I am retrieving XML from a web API, and the results returned are as such:

<ArrayOf__ptd_student_charges
    xmlns="http://schemas.datacontract.org/2004/07/something.something"
    xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <__ptd_student_charges>
        <accumulated_tuition>000.000</accumulated_tuition>
        <course_id>AAA-000/L</course_id>
        <invoice_date>01/01/2015</invoice_date>
        <lecturer_name>John Doe</lecturer_name>
        <net_tuition>000.000</net_tuition>
        <section_no>1</section_no>
        <semester>Summer</semester>
        <student_id>123456</student_id>
        <student_name>John Doe</student_name>
        <year>2015</year>
    </__ptd_student_charges>
    <__ptd_student_charges>
        <accumulated_tuition>000.000</accumulated_tuition>
        <course_id>AAA-000/L</course_id>
        <invoice_date>01/01/2015</invoice_date>
        <lecturer_name>John Doe</lecturer_name>
        <net_tuition>000.000</net_tuition>
        <section_no>1</section_no>
        <semester>Summer</semester>
        <student_id>123456</student_id>
        <student_name>John Doe</student_name>
        <year>2015</year>
    </__ptd_student_charges>  
</ArrayOf__ptd_student_charges>

I'm trying to deserialize this into an array of students. My student class is defined like this:

public class Student
{
    [System.Xml.Serialization.XmlElement("accumulated_tuiton")]
    public double AccumulatedTution { get; set; }

    [System.Xml.Serialization.XmlElement("net_tuiton")]
    public double NetTuiton { get; set; }

    [System.Xml.Serialization.XmlElement("course_id")]
    public string CourseID { get; set; }

    [System.Xml.Serialization.XmlElement("invoice_date")]
    public DateTime InvoiceDate { get; set; }

    [System.Xml.Serialization.XmlElement("lecturer_name")]
    public string LecturerName { get; set; }

    [System.Xml.Serialization.XmlElement("semester")]
    public string Semester { get; set; }

    [System.Xml.Serialization.XmlElement("student_id")]
    public string StudentId { get; set; }

    [System.Xml.Serialization.XmlElement("student_name")]
    public string StudentName { get; set; }

    [System.Xml.Serialization.XmlElement("year")]
    public string Year { get; set; }

    [System.Xml.Serialization.XmlElement("section_no")]
    public int Section { get; set; }
}

And my student collection is defined like this:

[System.Xml.Serialization.XmlRoot("ArrayOf__ptd_student_charges xmlns=\"http://schemas.datacontract.org/2004/07/something.something\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance")]
public class StudentCollection
{
    [XmlArray("ArrayOf__ptd_student_charges")]
    [XmlArrayItem("__ptd_student_charges", typeof(Student))]
    public Student[] StudentArray { get; set; }
}

I'm deserializing the results using this code:

private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    StudentCollection collection;

    HttpWebRequest request = WebRequest.Create(stringUrl) as HttpWebRequest;
    HttpWebResponse response = request.GetResponse() as HttpWebResponse;

    XmlTextReader reader = new XmlTextReader(response.GetResponseStream());

    XmlSerializer serializer = new XmlSerializer(typeof(StudentCollection));
    collection = (StudentCollection)serializer.Deserialize(reader);

    reader.Close();
}

Once I run this, I get an InvalidOperationException with a message

ArrayOf__ptd_student_charges xmlns='http://schemas.datacontract.org/2004/07/something.something'> was not expected.

I know that the xmlns:... shouldn't be in the first tag, but unfortunately it is and I'm unsure on how to proceed.

Community
  • 1
  • 1
kkyr
  • 3,785
  • 3
  • 29
  • 59

1 Answers1

1

Basically, you need to support the default XML namespace in your XML file - you can either do this by specifying it on the StudentCollection:

[System.Xml.Serialization.XmlRoot("ArrayOf__ptd_student_charges")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://schemas.datacontract.org/2004/07/something.something", IsNullable = false)]
public class StudentCollection
{
    [XmlArray("ArrayOf__ptd_student_charges")]
    [XmlArrayItem("__ptd_student_charges", typeof(Student))]
    public Student[] StudentArray { get; set; }
}

and the actual Student class:

[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://schemas.datacontract.org/2004/07/something.something", IsNullable = false)]
public class Student
{
   ..........
}

or you can specify it programmatically when you deserialize:

XmlSerializer serializer = new XmlSerializer(typeof(StudentCollection),
                                             "http://schemas.datacontract.org/2004/07/something.something");

That second parameter for the XmlSerializer is the default XML namespace to use when deserializing the XML content.

Extra tipp: if you ever have an XML file again, and you need to get the C# code classes that represent that XML - if you have Visual Studio 2012 or newer, just create a new code class, copy your XML file into the clipboard, and then use Edit > Paste Special > Paste XML as classes and you get all your C# including all XML attribute and XML namespaces and everything pasted into your Visual Studio right there

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 1
    Thank you! Both solutions worked, but on the first one I had to define the attribute on the same line else the compiler was complaining about a duplicate attribute, like this: [XmlRoot(ElementName = "ArrayOf__ptd_student_charges", Namespace = "http://schemas.datacontract.org/2004/07/something.something")] – kkyr Nov 03 '15 at 11:22
  • Great tip that's really helpful, too bad I can't up vote twice! – kkyr Nov 03 '15 at 11:27