2

I'm trying to use XDocument to read in XML and deserialize it to objects.

I want to take the following XML:

<r25:spaces xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xl="http://www.w3.org/1999/xlink" xmlns:r25="http://www.collegenet.com/r25" pubdate="2019-07-15T14:51:16-07:00" engine="accl">
  <r25:space crc="00000022" status="est" xl:href="space.xml?space_id=200">
    <r25:space_id>200</r25:space_id>
    <r25:space_name>LRN 0001</r25:space_name>
    <r25:formal_name>Learning Commons -Test Scheduling Room</r25:formal_name>
    <r25:partition_id xl:href="rmpart.xml?partition_id=2">2</r25:partition_id>
    <r25:last_mod_dt>2019-07-11T08:01:00-07:00</r25:last_mod_dt>
  </r25:space>
</r25:spaces>

and deserialize it to a List of spaces (where Space has the following definition):

public class Space
{
    public long space_id { get; set; }
    public string space_name { get; set; }
    public string formal_name { get; set; }
    public long partition_id { get ; set; }
    public DateTime last_mod_dt { get; set; }
}

I've only gotten so far as to get the XElement. It dies on the serializer

var doc = XDocument.Parse(result.Content);
XNamespace ns = "http://www.collegenet.com/r25";
XElement el = doc.Element(ns + "spaces");

foreach (var space in el.Elements())
{
    var serializer = new XmlSerializer(typeof(Space));
    var s = (Space)serializer.Deserialize(space.CreateReader());
}
4
  • Read about XmlSerializer Commented Jul 15, 2019 at 22:05
  • All I'm getting when I try to use XmlSerializer is "There is an error in XML document (0,0)", which isn't very helpful. I've updated my post with what I've tried. Commented Jul 15, 2019 at 22:12
  • If you are using XDocument, you aren't really deserializing-- you are parsing. You can either parse or deserialize-- there is no need to do both. If you're OK with a parsing approach, see David Browne's answer, which I am upvoting. Commented Jul 15, 2019 at 23:14
  • You're on the right lines here in that you were using the namespace for the XElement bit but when you retrieve that element and do the CreateReader() the namespaces are all still a factor and you have to let the XmlSerializer know about them using the serialization attribute XmlRootAttribute as shown in @SimplyGed's answer. You could also remove the XDocument stuff and read the XML straight from the string using an XmlTextReader. Commented Jul 15, 2019 at 23:32

4 Answers 4

3

You can simply use LINQ to XML here. e.g.

using System;
using System.Linq;
using System.Xml.Linq;

namespace ConsoleApp22
{

    public class Space
    {
        public long space_id { get; set; }
        public string space_name { get; set; }
        public string formal_name { get; set; }
        public long partition_id { get; set; }
        public DateTime last_mod { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var xml = @"
<r25:spaces xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xl=""http://www.w3.org/1999/xlink"" xmlns:r25=""http://www.collegenet.com/r25"" pubdate=""2019-07-15T14:51:16-07:00"" engine=""accl"">
  <r25:space crc=""00000022"" status=""est"" xl:href=""space.xml?space_id=200"">
    <r25:space_id>200</r25:space_id>
    <r25:space_name>LRN 0001</r25:space_name>
    <r25:formal_name>Learning Commons -Test Scheduling Room</r25:formal_name>
    <r25:partition_id xl:href=""rmpart.xml?partition_id=2"">2</r25:partition_id>
    <r25:last_mod_dt>2019-07-11T08:01:00-07:00</r25:last_mod_dt>
  </r25:space>
</r25:spaces>
";
            var doc = XDocument.Parse(xml);
            XNamespace ns = "http://www.collegenet.com/r25";

            var q = from e in doc.Element(ns + "spaces").Elements()
                    select new Space
                    {
                        space_id = (int)e.Element(ns + "space_id"),
                        space_name = (string)e.Element(ns + "space_name"),
                        formal_name = (string)e.Element(ns + "formal_name"),
                        partition_id = (long)e.Element(ns + "partition_id"),
                        last_mod = (DateTime)e.Element(ns + "last_mod_dt")
                    };

            var space = q.First();
        }
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Nice answer, but aren't you just duplicating what the deserializer does?
Avoiding the XmlSerializer, actually. Querying over the XML to create a custom projection is simple, useful, and not really something the XmlSerializer can do. So just an alternative approach.
Very nice solution. I'm still wanting to have automatic mapping, but if I need to, this works beautifully.
1

You can add the XmlRoot to your class to declare the namespace for that element:

[XmlRoot("space", Namespace = "http://www.collegenet.com/r25")]
public class Space
{
    public long space_id { get; set; }
    public string space_name { get; set; }
    public string formal_name { get; set; }
    public long partition_id { get; set; }
    public DateTime last_mod { get; set; }
}

The deserializer will now correctly read the XML as an object.

Comments

0

Use the the XSD tool to generate the class and then use XmlSerializer to populate the class. Like this.

MyClass myClass;
using (var stream = new FileStream("myClass.xml", FileMode.Open))
{
    var serializer = new XmlSerializer(typeof(MyClass));
    myClass = serializer.Deserialize(stream);
}

Comments

0

I found a website that will take XML and create the proper deserialization classes. Xml2CSharp, which created the following classes that allowed the deserialization to work:

[XmlRoot(ElementName="partition_id", Namespace="http://www.collegenet.com/r25")]
public class Partition_id {
    [XmlAttribute(AttributeName="href", Namespace="http://www.w3.org/1999/xlink")]
    public string Href { get; set; }
    [XmlText]
    public string Text { get; set; }
}

[XmlRoot(ElementName="space", Namespace="http://www.collegenet.com/r25")]
public class Space {
    [XmlElement(ElementName="space_id", Namespace="http://www.collegenet.com/r25")]
    public string Space_id { get; set; }
    [XmlElement(ElementName="space_name", Namespace="http://www.collegenet.com/r25")]
    public string Space_name { get; set; }
    [XmlElement(ElementName="formal_name", Namespace="http://www.collegenet.com/r25")]
    public string Formal_name { get; set; }
    [XmlElement(ElementName="partition_id", Namespace="http://www.collegenet.com/r25")]
    public Partition_id Partition_id { get; set; }
    [XmlElement(ElementName="last_mod_dt", Namespace="http://www.collegenet.com/r25")]
    public string Last_mod_dt { get; set; }
    [XmlAttribute(AttributeName="crc")]
    public string Crc { get; set; }
    [XmlAttribute(AttributeName="status")]
    public string Status { get; set; }
    [XmlAttribute(AttributeName="href", Namespace="http://www.w3.org/1999/xlink")]
    public string Href { get; set; }
}

[XmlRoot(ElementName="spaces", Namespace="http://www.collegenet.com/r25")]
public class Spaces {
    [XmlElement(ElementName="space", Namespace="http://www.collegenet.com/r25")]
    public Space Space { get; set; }
    [XmlAttribute(AttributeName="xsi", Namespace="http://www.w3.org/2000/xmlns/")]
    public string Xsi { get; set; }
    [XmlAttribute(AttributeName="xl", Namespace="http://www.w3.org/2000/xmlns/")]
    public string Xl { get; set; }
    [XmlAttribute(AttributeName="r25", Namespace="http://www.w3.org/2000/xmlns/")]
    public string R25 { get; set; }
    [XmlAttribute(AttributeName="pubdate")]
    public string Pubdate { get; set; }
    [XmlAttribute(AttributeName="engine")]
    public string Engine { get; set; }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.