我正在尝试使用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>
请帮忙!我很紧张。
答案 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")
如果节点不存在则返回int
或null
值。结合??
运算符,它是一种读取值的简洁方法。强制转换将使用字符串值和基本值类型,如int
或decimal
。 (仅为了证明这一点,我将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() { }
}
希望这有帮助!