0

I'm trying to convert a XML file to a list. The XML file contains different products, and each product has different values, e.g.:

<product>
    <id></id>
    <name>Commentarii de Bello Gallico et Civili</name>
    <price>449</price>
    <type>Book</type>
    <author>Gaius Julius Caesar</author>
    <genre>Historia</genre>
    <format>Inbunden</format>
</product>
    <product>
    <id></id>
    <name>Katana Zero</name>
    <price>199</price>
    <type>Game</type>
    <platform>PC, Switch</platform>
</product>

The problem is that some elements does not have all fields, some books can look like this for example:

<product>
    <id></id>
    <name>House of Leaves</name>
    <price>49</price>
    <type>Bok</type>
    <author>Mark Z. Danielewski</author>
    <genre>Romance</genre>
</product>

When I try adding these elements to the list, it works until I get an element that does not have all fields. When that happens, I get "System.NullReferenceException: 'Object reference not set to an instance of an object'."

List<Product> products= new List<Product>();
XElement xelement = XElement.Load(path);
IEnumerable<XElement> pr = xelement.Elements();

foreach (var p in pr)
    {
        switch (p.Element("type").Value)
        {
            case "Book":
                temp.Add(new Book(1, int.Parse(employee.Element("price").Value), 
                    0 , 
                    p.Element("name").Value, 
                    p.Element("author").Value,
                    p.Element("genre").Value, 
                    p.Element("format").Value");
                break;
    }

What I would like is to get a null value or "Not specified" when that happens, but I don't know how to do that in a good way. All I can think of are try catch for each variable but that seems uneccesary complicated.

How can I handle these cases in a good way?

  • I have a question, why not direct deserialization from XML to object instead of manually parsing? It will be one line of code and a class that is auto generated by Visual studio. Sure you can have other Ctor or null check but why are you doint if that way? and are you interressed in the other way ? – Drag and Drop Apr 01 '21 at 12:22
  • Does this answer your question? [How to deserialize xml to object](https://stackoverflow.com/questions/10518372/how-to-deserialize-xml-to-object) – Drag and Drop Apr 01 '21 at 12:32
  • I did not know that it was an option. Steve Harris answer worked for what I intended to do, but I'm going to try doing the serialization instead, seems really neat. Thanks! – Axel Pettersson Apr 01 '21 at 13:28

2 Answers2

1

Use a null check - ?

p.Element("name")?.Value, 
p.Element("author")?.Value,
p.Element("genre")?.Value, 
p.Element("format")?.Value");
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Steve Harris
  • 5,014
  • 1
  • 10
  • 25
0

I usually use a nested dictionary :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication186
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            Dictionary<string, Dictionary<string, string>> dict = doc.Descendants("product")
                .GroupBy(x => (string)x.Element("name"), y => y.Elements()
                    .GroupBy(a => a.Name.LocalName, b => (string)b)
                    .ToDictionary(a => a.Key, b => b.FirstOrDefault()))
                .ToDictionary(x => x.Key, y => y.FirstOrDefault());
        }
    }
}
jdweng
  • 33,250
  • 2
  • 15
  • 20