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 specifiesxsi:nil="true"
or leaves the element out entirely, depending on whether anillable="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.