0

I have large number of Xml files that contain double, int, DateTime, string, lists of objects .. etc. Mix of variable types similar to this:

<?xml version="1.0" encoding="utf-8"?>
<Verification xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <SerialNumber>1</SerialNumber>
  <Description>V1 From File</Description>
  <DateCreated>2016-04-22T09:27:54.193</DateCreated>
  <DesiredX>1.000000</DesiredX>
  <DesiredTargets count="3">
    <Sample X1="535.108154296875" X2="1058.36315917969" Y1="780.292175292969" Y2="1037.53625488281" A="-44.5051406645421" B="-2.8002082198978" C="-0.211281331705749" DifferenceA="-44.5051406645421" DifferenceB="-2.8002082198978" DifferenceC="-0.211281331705749" ReferenceNumber="0" TimeTaken="Tuesday, April 26, 2016 2:25:43 PM" />
    <Sample X1="529.666198730469" X2="533.695007324219" Y1="854.45654296875" Y2="514.573974609375" A="62.1131427426299" B="-4.93194374266585" C="-0.383094414887779" DifferenceA="62.1131427426299" DifferenceB="-4.93194374266585" DifferenceC="-0.383094414887779" ReferenceNumber="1" TimeTaken="Tuesday, April 26, 2016 2:25:43 PM" />
    <Sample X1="172.242752075195" X2="777.789245605469" Y1="334.160064697266" Y2="740.525268554688" A="9.54891420214495" B="91.256891073657" C="0.329283687878274" DifferenceA="9.54891420214495" DifferenceB="91.256891073657" DifferenceC="0.329283687878274" ReferenceNumber="2" TimeTaken="Tuesday, April 26, 2016 2:25:45 PM" />
  </DesiredTargets>
</Verification>

The list of objects is of type Sample, default constructor:

public Sample(Test targetTest, double newX1, double newX2, double newY1, double newY2, double newA, double newB, double newC, int sampleNum)

Class Verification which every Xml file will be loaded to an instance of it:

public class Verification
{
    public int SerialNumber { get; set; }
    public int ReferenceCount { get; set; }
    public string Description { get; set; }
    public DateTime DateCreated {get; set; }
    public double DesiredX { get; set; }
    public List<Sample> DesiredTargets { get; set; }
    // ..
    // other variables and functions
}

Mission: Load the Xml files

Purpose: I don't want to change every file's structure or tags to match certain code pattern like suggested here Load in a simple list of objects

Vision:

  • Any variables that doesn't exist in the Xml, should be set as null (happens by default?) Here I know that the parameter targetTest is missing, which the Sample constructor needs, but what if I don't know what is missing? Also I know that ReferenceCount for class Verification is not in the xml.. etc.

  • A code that matches the files and not edit all files to match a code

My code works using XmlSerializer when I had no List<Sample>. Now the file has a List<Sample> and the below code uses XDocument but pops an error:

Object reference not set to an instance of an object

using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
// ..

public void LoadFromFile(string path)
{
    // stuff
    // ..
    // to load list of Sample
    XDocument XmlReader = XDocument.Load(path);

    // pops the error here
    DesiredTargets =
        XmlReader.Root.Elements("DesiredTargets")
        .Select(h => new Sample(
            null,
            double.Parse(h.Element("X1").Value),
            double.Parse(h.Element("X2").Value),
            double.Parse(h.Element("Y1").Value),
            double.Parse(h.Element("Y2").Value),
            double.Parse(h.Element("A").Value),
            double.Parse(h.Element("B").Value),
            double.Parse(h.Element("C").Value),
            int.Parse(h.Element("ReferenceNumber").Value)
            ))
        .ToList();

        // I don't have the code using XDocument for other variables yet but it works when there is no List<> using XmlSerializer
}
Community
  • 1
  • 1
Khalil Khalaf
  • 9,259
  • 11
  • 62
  • 104
  • @ Mephy but this happens before my application loads. I didn't know that so I will edit it **Edit**: I just noticed that yes it compiles but this code executes right on application load. I confused that – Khalil Khalaf Apr 27 '16 at 14:11
  • Also a good idea not to use Pascal casing for variables like you're doing for XmlReader as they can easily be confused worth rules types by other devs or even you or the compiler. There is actually an XmlReader class in the .NET Framework, for example. – Heath Apr 27 '16 at 15:05

1 Answers1

1

Your code is trying to read child elements of DesiredTargets using h.Element("name").Value. If an element is not present, Element returns null and the call to the Value property will throw a NullReferenceException.

Not one of the 7 elements you're trying to read actually exist, so all of these will cause the problem you're seeing. They are not elements, they are attributes of the Sample element. As an aside, there are built-in explicit conversions in LINQ to XML that mean you don't have to parse the strings:

So, something like this would actually work:

doc.Descendants("DesiredTargets")
    .Elements("Sample")
    .Select(x => new Sample(
        null,
        (double)x.Attribute("X1"),
        (double)x.Attribute("X2"),
        (double)x.Attribute("Y1"),
        (double)x.Attribute("Y2"),
        (double)x.Attribute("A"),
        (double)x.Attribute("B"),
        (double)x.Attribute("C"),
        (int)x.Attribute("ReferenceNumber"))
    ).ToList();

That said, you'd be far better off using XmlSerializer than hand coding the serialisation yourself. List<T> shouldn't be a problem.

Charles Mager
  • 25,735
  • 2
  • 35
  • 45
  • Worked for the list. Thanks! I have another problem now, regarding the rest variable of `Verification` class could you help me? – Khalil Khalaf Apr 27 '16 at 15:21