【发布时间】:2016-01-08 21:29:41
【问题描述】:
我有一个非常大的 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 条)时,我收到未将对象引用设置为对象实例的错误。
这是有道理的,因为被选中的节点不存在。 在阅读了很多帖子之后,看起来我应该做一个三元运算符来解释 null 父级。像这样的:
let homePhoneAttribute = x.Element(wd + "Home_Phone") == null ? "" : x.Element(wd + "Home_Phone").Attributes(wd + "Descriptor").FirstOrDefault()
这不太对: 无法确定条件表达式的类型,因为 'string' 和 '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() 铸造?
【问题讨论】:
-
您获得了第一条记录,因为您在查询中有
FirstOrDefault()。稍微不同的查询会起作用吗 -let homePhoneAttribute = (string)x.Element(wd + "Home_Phone") == null ? String.Empty : x.Element(wd + "Home_Phone").Attributes(wd + "Descriptor");- 请注意,这会给你一个集合,然后你可以用你想要的东西来做。 -
感谢蒂姆的帮助......这也不太奏效。仍然存在转换问题:无法确定条件表达式的类型,因为 'string' 和 'System.Collections.Generic.IEnumerable
' 之间没有隐式转换 -
可能是这样的:
let homePhoneAttribute = (string)x.Element(wd + "Home_Phone") == null ? null : x.Element(wd + "Home_Phone").Attributes(wd + "Descriptor");- 将String.Empty替换为null。尽管这可能会导致下游问题。也许不是null,而是使用new IEnumerable<XAttribute>();或类似的东西? -
嗨,蒂姆 - 我仍然需要选择
XAttribute Value. homePhoneAttribute.FirstOrDefault().Value.当我这样做时,它会再次中断转换。如果我不使用 FirstOrDefault(),我会得到这个'IEnumerable<XAttribute>' does not contain a definition for 'Value' and no extension method 'Value' accepting a first argument of type 'IEnumerable<XAttribute>' could be found