使用 C 解析 XML 文件 extrate 中的 Null 值时出错#

Getting Error while Parsing the Null value in XML file extrate using C#

提问人:skt 提问时间:8/19/2022 最后编辑:Olivier Jacot-Descombesskt 更新时间:8/19/2022 访问量:706

问:

我需要有关XML文件解析的小帮助。我在每个循环迭代时收到错误,而 XML 文件中的 Null 值。 如何使用具有 Null 值的不同数据类型进行解析。

源 XML 文件:

<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>

我收到 SensorBlobVersion 的错误。它是空的。错误:“输入字符串的格式不正确。

当我将调试点放在 SensorBlobVersion 时,我可以看到 Null,如下所示:

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

示例源代码:

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; }
            }

        }
    }
}
C# LINQ-to-XML

评论

0赞 jdweng 8/19/2022
以下作品: int version = 0;布尔值 isInt = int。TryParse((字符串)el2.Element(“SensorBlobVersion”),输出版本);我。SensorBlobVersion = 是Int ?版本 : null;

答:

0赞 jdweng 8/19/2022 #1

我让代码简单了一点:

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; }
        }

    }
0赞 dbc 8/19/2022 #2

属性 xsi:nil 是一个 w3c 标准属性,指示元素没有内容。Microsoft 有时会将值序列化为空 XML 元素,如文档中指定的那样:XmlSerializernullxsi:nil="true"

将对象序列化为 XML 文档时:如果类遇到对应于 XML 元素的对象的空引用,则它会生成一个指定或完全忽略该元素的元素,具体取决于是否应用设置。XmlSerializerxsi:nil="true"nillable="true"

如果 XML 是使用具有 null 值属性的元素生成的,并且您使用 LINQ to XML 手动分析,则需要手动检查它们。xsi:nil="true"

首先,介绍以下扩展方法:

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";
}

现在修改代码,如下所示:

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);

在这里,我假设您需要区分缺少元素和 null 元素的情况。如果不需要区分,可以将两种情况分配给相同的值,例如:<SensorBlobVersion><SensorBlobVersion xsi:nil="true" />

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

演示小提琴在这里