使用Linq到xml从Xml文件填充列表

时间:2014-01-22 09:06:58

标签: c# xml linq list

我正在尝试使用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>

请帮忙!我很紧张。

1 个答案:

答案 0 :(得分:1)

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

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

  • 一个Xml文档,其中一个<Kunde>节点没有其中一个节点 值节点也会导致异常。例如,如果有 没有<Vorname>值,那么这段代码将引发异常 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();

我已经整理了一个小型控制台应用程序,测试了几个样本xmls:

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() { }
}

希望这有帮助!