【问题标题】:Fill list from Xml file using Linq to xml使用 Linq to xml 从 Xml 文件填充列表
【发布时间】:2014-01-22 09:06:57
【问题描述】:

我正在尝试使用 linq 从 xml 文件中填充客户端列表,但我总是得到这个空异常:Object reference not set to an instance of an object.。这是我的代码,从 Client 类开始:

public class Client
{
    // Personne Physique
    public string IdClient { get; set; }
    public string NomClient { get; set; }
    public string PrenomClient { get; set; }
    public Client(){}
}

填充列表的代码:

var doc = XDocument.Load(pathXml);
List<Client> lc = doc.Descendants("Anzeige")
                     .FirstOrDefault()
                     .Descendants("Kunde")
                     .Select(p => new Client()
                     {
                         IdClient = p.Element("KundNr").Value,
                         NomClient = p.Element("Nachname").Value,
                         PrenomClient = p.Element("Vorname").Value
                     }).ToList<Client>();

xml 文件如下所示:

<Anzeige>
  <Kunde>
     <KundNr>111</KundNr>
     <Nachname>111</Nachname>
     <Vorname>111</Vorname> 
  </Kunde>
</Anzeige>

请帮忙!时间紧迫。

【问题讨论】:

  • 您必须将属性 (XmlElement) 放在属性上,例如 [XmlAttribute("KundNr")] 在 IdClient 上等等
  • 能否给我写个例子,我写的不是很好,谢谢
  • 好的,让我先在我的系统上做。
  • 为什么第三次修改获得批准?
  • 好的,非常感谢

标签: c# xml linq list


【解决方案1】:

该代码适用于您发布的示例 Xml。 但是,您没有处理某些代码会中断的情况。例如:

  • 没有 &lt;Anzeige&gt; 节点的 Xml 文档将导致空异常 在doc.Descendants("Anzeige").FirstOrDefault().Descendants("Kunde") 因为FirstOrDefault() 的结果将为空。

  • 一个 Xml 文档,其中 &lt;Kunde&gt; 节点之一没有 值节点也会导致异常。例如,如果有 没有&lt;Vorname&gt;值那么这段代码会抛出异常 p.Element("Vorname").Value

您可以稍微调整一下代码来处理这些情况。

编辑:您可以使用Elements 而不是Descendants 来强制一个xml,其中Anzeige 节点直接位于根之后,并且Kunde 是Anzeige 的直接子代。我还编辑了我的答案,以利用可以直接在 XElement 上使用的转换运算符。这样(int?) p.Element("KundNr") 在节点不存在时返回intnull 值。结合?? 运算符,它是一种读取值的干净方式。强制转换适用于字符串值和基本值类型,如intdecimal。 (只是为了证明这一点,我将IdClient 更改为int

如果您尝试转换为int? 并且节点值是无法在int 上转换的值,例如"ABC",您仍然可能会遇到错误。但是,您将所有字段都作为字符串,所以这对您来说应该不是问题:

var clients = doc.Descendants("Anzeige").Descendants("Kunde").Select(p => new Client()
{
    IdClient = (int?) p.Element("KundNr") ?? -1,
    NomClient = (string) p.Element("Nachname") ?? String.Empty,
    PrenomClient = (string) p.Element("Vorname") ?? String.Empty
}).ToList();

我已经组装了一个小型控制台应用程序来测试一些示例 xml:

static void Main(string[] args)
{
    var doc = XDocument.Parse(
            @"<Anzeige>
                <Kunde>
                    <KundNr>111</KundNr>
                    <Nachname>111</Nachname>
                    <Vorname>111</Vorname> 
                </Kunde>
                <Kunde>
                    <KundNr>222</KundNr>                            
                    <Nachname>222</Nachname>
                    <Vorname>222</Vorname> 
                </Kunde>
            </Anzeige>");
    ExtractClients(doc);

    var docWithMissingValues = XDocument.Parse(
            @"<Anzeige>
                <Kunde>
                    <KundNr>111</KundNr>
                    <Vorname>111</Vorname> 
                </Kunde>
                <Kunde>
                    <KundNr>222</KundNr>                            
                    <Nachname>222</Nachname>
                </Kunde>
                <Kunde>
                </Kunde>
            </Anzeige>");
    ExtractClients(docWithMissingValues);

    var docWithoutAnzeigeNode = XDocument.Parse(
            @"<AnotherNode>
                <Kunde>
                    <KundNr>111</KundNr>
                    <Vorname>111</Vorname> 
                </Kunde>
            </AnotherNode>");
    ExtractClients(docWithoutAnzeigeNode);

    var docWithoutKundeNodes = XDocument.Parse(
            @"<Anzeige>
                <OtherNode></OtherNode>
            </Anzeige>");
    ExtractClients(docWithoutKundeNodes);

    var emptyDoc = new XDocument();
    ExtractClients(emptyDoc);

    Console.ReadLine();
}

private static void ExtractClients(XDocument doc)
{
    var clients = doc.Descendants("Anzeige").Descendants("Kunde").Select(p => new Client()
    {
        //You can manually get the value like this:
        //IdClient = p.Element("KundNr") != null ? p.Element("KundNr").Value : String.Empty,
        //NomClient = p.Element("Nachname") != null ? p.Element("Nachname").Value : String.Empty,
        //PrenomClient = p.Element("Vorname") != null ? p.Element("Vorname").Value : String.Empty

        //Or directly cast the node value to the type (value types or strings) required like:
        IdClient = (int?) p.Element("KundNr") ?? -1,
        NomClient = (string) p.Element("Nachname") ?? String.Empty,
        PrenomClient = (string) p.Element("Vorname") ?? String.Empty
    }).ToList();

    Console.WriteLine();
    foreach (var client in clients)
    {
        Console.WriteLine("{0},{1},{2}", client.IdClient, client.NomClient, client.PrenomClient);
    }
    Console.WriteLine(new string('-',30));
}

public class Client
{
    // Personne Physique
    public int IdClient { get; set; }
    public string NomClient { get; set; }
    public string PrenomClient { get; set; }
    public Client() { }
}

希望这会有所帮助!

【讨论】:

  • 我想在 "ar clients = doc.Descendants("Anzeige").Descendants("Kunde").Select(p => new Client()" 上创建一个 !=null 控件,如何可以吗,谢谢
  • @user1503496 我在回答中添加了更多信息。关于那里的空值,请查看我添加的示例。您会注意到链接Descendants(甚至Elements)调用可以很好地处理没有结果的情况,以一个空的客户端列表结束。 (事实上​​,最后 3 个测试最终会出现在一个空的客户端列表中)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多