在LINQ中使用let时,如何处理丢失的XML节点
本文关键字:处理 节点 XML 何处理 LINQ let | 更新日期: 2023-09-27 18:29:30
我有一个很大的XML文档,其中缺少一些节点。
良好的XML:
<wd:Job_Family wd:Descriptor="Research/Extension">
<wd:Home_Phone wd:Descriptor="+1 (555) 555-0731">
<wd:ID wd:type="WID">89bfac800b6b41da94e1d1a22b14e66a</wd:ID>
</wd:Home_Phone>
<wd:Home_Address wd:Descriptor="1 Beverly Dr">
错误的XML:
<wd:Job_Family wd:Descriptor="Research/Extension">
***MISSING ***
<wd:Home_Address wd:Descriptor="1 Beverly Dr">
我选择数据的方式是这样的:
List<Employee> employee = new List<Employee>();
try
{
// Get the xml file as stream
StreamReader reader = new StreamReader(outputFileNameAndPath);
// Read the whole contents and return as a string
string xmlString = reader.ReadToEnd();
XDocument doc = XDocument.Parse(xmlString);
XNamespace wd = "urn:com.something.report/Worker_ID_Data_-_Store";
IEnumerable<XElement> worker = doc.Descendants(wd + "Report_Entry");
var query = (from x in doc.Descendants(wd + "Report_Entry")
let jobFamilyAttribute = x.Element(wd + "Job_Family_Group").Attributes(wd + "Descriptor").FirstOrDefault()
select new Employee
{
JobFamily = jobFamilyAttribute.Value
});
employee.AddRange(query);
}
catch (Exception ex)
{
log.Error("An error occurred while trying to parse the XML: " + ex);
}
return employee;
这很管用。我选择了一些额外的节点,但为了简单起见,这已经足够了。
现在,当我尝试选择一个丢失的节点(可能是1000条记录中的1条)时,我会收到未设置为对象实例的Object引用的错误。
这是有道理的,因为被选中的节点不在那里。在阅读了许多帖子后,我似乎应该做一个三元运算符来解释空父级。类似这样的东西:
let homePhoneAttribute = x.Element(wd + "Home_Phone") == null ? "" : x.Element(wd + "Home_Phone").Attributes(wd + "Descriptor").FirstOrDefault()
这不太正确:无法确定条件表达式的类型,因为"string"answers"System.Xml.Linq.XAttribute"之间没有隐式转换
即使我将它强制转换为字符串或对象,它也会编译,但当我寻址范围时,我只得到所有记录的第一个值:
let homePhoneAttribute = x.Element(wd + "Home_Phone") == null ? (string)"" : x.Element(wd + "Home_Phone").Attributes(wd + "Descriptor").FirstOrDefault().Value
所以,我的长篇大论的问题是,如何在仍然能够使用let进行选择的情况下正确地转换和解释空节点?
我认为这一定是某种DefaultIfEmpty()
选角?
您可以使用以下表达式:
let homePhoneAttribute = (string)x.Elements(wd + "Home_Phone")
.Attributes(wd + "Descriptor")
.FirstOrDefault()
通过使用x.Elements()
而不是单数形式Element()
,可以避免在找不到元素的情况下出现异常。然后,通过将FirstOrDefault()
返回值强制转换为string
,可以避免返回值为null
时出现异常。
dotnetfiddle demo
演示显示,当wd:Home_Phone
元素丢失时,homePhoneAttribute
变量只包含空字符串。未引发异常。
更新:
如果您想要多个属性值(List<string>
),而不仅仅是第一个,您可以按照如下方式修改上面的LINQ:
let homePhoneAttribute = x.Elements(wd + "Home_Phone")
.Attributes(wd + "Descriptor")
.Select(o => o.Value)
.ToList()