0

XML file looks like this:

<?xml version="1.0"?>
<catalog>
    <book id="bk101">
        <author>Gambardella, Matthew</author>
        <title>XML Developer's Guide</title>
        <genre>Computer</genre>
        <price>44.95</price>
        <publish_date>2000-10-01</publish_date>
        <description>An in-depth look at creating applications with XML.</description>
    </book>
    <book id="bk102">
        <author>Ralls, Kim</author>
        <title>Midnight Rain</title>
        <genre>Fantasy</genre>
        <price>5.95</price>
        <publish_date>2000-12-16</publish_date>
        <description>A former architect battles corporate zombies, an evil sorceress, and her own childhood to become queen of the world.</description>
    </book>
</catalog>

I need to read all data to my class:

public class Book
{
    public string Id { get; set; }

    public string Author { get; set; }
    public string Title { get; set; }
    public Genre Genre { get; set; }
    public decimal Price { get; set; }
    public DateTime PublishDate { get; set; }
    public string Description { get; set; }

}

Below code doesn't work, I can grab bookId from node, but not Title, Author.. How to achieve that result? This is what I have so far:

const string filePath = @"C:\Users\Michał\Desktop\books.xml";

XDocument xmlDoc = XDocument.Load(filePath);

var dupa = xmlDoc
    .Descendants("book")
    .Select(x => new Book()
    {
        Id = (string) x.Attribute("bookid"),

        Title = (string) x.Attribute("title") // Title is empty after that code runs

    }).ToList();
dbc
  • 104,963
  • 20
  • 228
  • 340
mike_pl
  • 121
  • 1
  • 2
  • 12

1 Answers1

1

id is an attribute of <book> but the other nodes are child XML elements so you need to access them using XContainer.Element(XName name):

var dupa = xmlDoc
    .Descendants("book")
    .Select(x => new Book
    {
        Id = (string)x.Attribute("bookid"),
        Author = (string)x.Element("author"),
        Title = (string)x.Element("title"),
        Genre = (Genre)Enum.Parse(typeof(Genre), (string)x.Element("genre")),
        Price = (decimal)x.Element("price"),
        PublishDate = (DateTime)x.Element("publish_date"),
        Description = (string)x.Element("description"),
    }).ToList();

Here I am assuming that Genre is an enum that looks something like:

public enum Genre
{
    Computer,
    Fantasy,
};

Sample fiddle #1.

Alternatively, you could create a Catalog type that contains your list of books, annotate it and Book with attributes that control XML serialization, and deserializing everything using XmlSerializer.

Define your types like so:

[XmlRoot(ElementName = "book")]
public class Book
{
    [XmlElement(ElementName = "author")]
    public string Author { get; set; }
    [XmlElement(ElementName = "title")]
    public string Title { get; set; }
    [XmlElement(ElementName = "genre")]
    public Genre Genre { get; set; }
    [XmlElement(ElementName = "price")]
    public decimal Price { get; set; }
    [XmlElement(ElementName = "publish_date")]
    public string PublishDate { get; set; }
    [XmlElement(ElementName = "description")]
    public string Description { get; set; }
    [XmlAttribute(AttributeName = "id")]
    public string Id { get; set; }
}

[XmlRoot(ElementName = "catalog")]
public class Catalog
{
    [XmlElement(ElementName = "book")]
    public List<Book> Books { get; set; }
}

public enum Genre
{
    Computer,
    Fantasy,
};

And then deserialize as follows:

List<Book> dupa;
using (var reader = XmlReader.Create(filePath))
{
    var serializer = new XmlSerializer(typeof(Catalog));
    dupa = ((Catalog)serializer.Deserialize(reader)).Books;
}

Sample fiddle #2.

Notes:

  • Consider changing Genre from an enum to a string. With your current model, deserialization will fail if new genres are later added to the XML.

  • There are a variety of tools to auto-generate types from XML that are compatible with XmlSerializer. I used https://xmltocsharp.azurewebsites.net/ and then modified the property names and types as required. Another option is xsd.exe. For more see Generate C# class from XML.

dbc
  • 104,963
  • 20
  • 228
  • 340