Home > Back-end >  Getting Error while Parsing the Null value in XML file extrate using C#
Getting Error while Parsing the Null value in XML file extrate using C#

Time:08-19

I need small help for XML file Parsing. I am getting the error while Null value in XML file while iterating by for each loop. How to parse with different data Type with Null value.

Source XML file :

<XMLList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <measList>
    <Measurement>
      <MeasurementGuid>87ae41e0-e9ec-4570-83c1-75fbfc96db17</MeasurementGuid>   
      <SequenceNumber>953</SequenceNumber>
      <Time>2020-10-07T15:39:06</Time>
      <SensorBlobVersion xsi:nil="true" />     
    </Measurement>

    <Measurement>
      <MeasurementGuid>1243234-e9ec-2324-83c1-43fbfc96db17</MeasurementGuid>   
      <SequenceNumber>111</SequenceNumber>
      <Time>2022-11-07T15:39:06</Time>
      <SensorBlobVersion xsi:nil="true" />     
    </Measurement>

 </measList>
</XMLList>

I am getting the error for SensorBlobVersion. It's Null. Error : "Input string was not in a correct format."

When I put the debug point at SensorBlobVersion then I can see the Null as below :

"<SensorBlobVersion xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />"

Sample Source Code :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XMLFileUploader
{
    using System.Linq;
    using System.Xml;
    using System.Xml.Linq;

    namespace XMLFileUploader
    {
        public static class ExtractLogFile
        {
            public static void ExtractData(string filePath)
            {
                XElement root = XElement.Load(filePath);
                IEnumerable<XElement> tests =
                                     from el in root.Elements("measList") 
                                     select el;

                IEnumerable<XElement> measList =
                  from el2 in tests.Elements("Measurement")
                  select el2;

                foreach (XElement el2 in measList)
                {
                    Measurement mes = new Measurement();

                    if (el2.NodeType == XmlNodeType.Element && el2.Name == "Measurement")
                    {
                        mes.MeasurementInfoGuid = (String)el2.Element("MeasurementGuid");
                        mes.SequenceNumber = (int)el2.Element("SequenceNumber");
                        mes.Time = (DateTime)el2.Element("Time");

                        if (el2.Element("SensorBlobVersion") == null)
                        {
                            mes.SensorBlobVersion = 0;
                        }
                        else
                        {
                            mes.SensorBlobVersion = (int?)(el2.Element("SensorBlobVersion"));   // **ERROR AT THIS LINE**
                        }
                    }
                }
            }

            public class Measurement
            {
                public String MeasurementInfoGuid { get; set; }
                public int SequenceNumber { get; set; }
                public DateTime Time { get; set; }
                public int? SensorBlobVersion { get; set; }
            }

        }
    }
}

CodePudding user response:

I made code a little simpler :

public static class ExtractLogFile
    {
        public static void ExtractData(string filePath)
        {
            XDocument doc = XDocument.Load(filePath);
           
            IEnumerable<XElement> measList = doc.Descendants("Measurement");

            foreach (XElement el2 in measList)
            {
                Measurement mes = new Measurement();

                mes.MeasurementInfoGuid = (String)el2.Element("MeasurementGuid");
                mes.SequenceNumber = (int)el2.Element("SequenceNumber");
                mes.Time = (DateTime)el2.Element("Time");

                if (el2.Element("SensorBlobVersion") == null)
                {
                    mes.SensorBlobVersion = 0;
                }
                else
                {
                    int version = 0; 
                    Boolean isInt = int.TryParse((string)el2.Element("SensorBlobVersion"),out version );
                    mes.SensorBlobVersion = isInt ? version : null;
                }
            }
        }

        public class Measurement
        {
            public String MeasurementInfoGuid { get; set; }
            public int SequenceNumber { get; set; }
            public DateTime Time { get; set; }
            public int? SensorBlobVersion { get; set; }
        }

    }

CodePudding user response:

The attribute xsi:nil is a w3c standard attribute that indicates that an element has no content. Microsoft's XmlSerializer will sometimes serialize a null value as an empty XML element with xsi:nil="true" as specified in the docs:

When serializing objects into an XML document: If the XmlSerializer class encounters a null reference for an object corresponding to an XML element, it either generates an element that specifies xsi:nil="true" or leaves the element out entirely, depending on whether a nillable="true" setting applies.

If your XML was generated with elements that have xsi:nil="true" attributes for null values and you are parsing manually using LINQ to XML, you will need to check for them manually.

First, introduce the following extension method:

public static class XNodeExtensions
{
    static readonly XNamespace xsi = @"http://www.w3.org/2001/XMLSchema-instance";
    static readonly XName xsiNil = xsi   "nil";
    
    public static bool IsNull(this XElement? element) => element == null || element.Attribute(xsiNil)?.Value == "true";
}

And now modify your code as follows:

var sensorBlobVersionElement = el2.Element("SensorBlobVersion");

if (sensorBlobVersionElement == null)
    mes.SensorBlobVersion = 0; // Element was missing, assign to 0
else if (sensorBlobVersionElement.IsNull()) 
    mes.SensorBlobVersion = null; // Element was present but explicitly null
else
    mes.SensorBlobVersion = (int?)(sensorBlobVersionElement);

Here I am assuming you need to distinguish between the case of a missing <SensorBlobVersion> element and a null <SensorBlobVersion xsi:nil="true" /> element. If you don't need to distinguish you could assign both cases to the same value, e.g.:

if (sensorBlobVersionElement.IsNull()) 
    mes.SensorBlobVersion = null; // Element was missing or null
else
    mes.SensorBlobVersion = (int?)(sensorBlobVersionElement);

Demo fiddle here.

  • Related