【问题标题】:c# linq to xml query helpc# linq to xml查询帮助
【发布时间】:2025-08-26 17:40:02
【问题描述】:

让我们假设一个名为 data.xml 的 xml 文件具有以下内容:

<root>
<record>
<id>1</id>
<name>test 1</name>
<resume>this is the resume</resume>
<specs>these are the specs</specs>
</record>
<record>
<id>2</id>
<name>test 2</name>
<resume>this is the resume 2</resume>
</record>
<record>
<id>3</id>
<name>test 3</name>
<specs>these are the specs 3</specs>
</record>
</root>

我需要搜索这些字段(id、name、resume 或 specs)中的任何一个包含给定值的所有记录。我已经创建了这段代码

XDocument DOC = XDocument.Load("data.xml");
IEnumerable<ProductRecord> results = from obj in DOC.Descendants("record")
     where 
obj.Element("id").Value.Contains(valueToSearch) ||
obj.Element("name").Value.Contains(valueToSearch) ||
obj.Element("resume").Value.Contains(valueToSearch) ||
obj.Element("specs").Value.Contains(valueToSearch)
     select new ProductRecord {
ID = obj.Element("id").Value,
Name = obj.Element("name").Value,
Resume = obj.Element("resume").Value,
Specs = obj.Element("specs").Value
     };

此代码引发 NullReference 错误,因为并非所有记录都具有所有字段。 在定义要应用的条件之前,如何测试当前记录是否具有给定元素?前任。记录[@ID=3] 没有简历。

提前致谢

【问题讨论】:

    标签: c# c#-4.0 linq-to-xml xelement


    【解决方案1】:

    您可以编写如下扩展方法:

    public static class XMLExtension
    {
        public static string GetValue(this XElement input)
        {
            if (input != null)
                return input.Value;
            return null;
        }
    
        public static bool XMLContains(this string input, string value)
        {
            if (string.IsNullOrEmpty(input))
                return false;
            return input.Contains(value);
        }
    }
    

    并按如下方式使用:

    IEnumerable<ProductRecord> results = from obj in DOC.Descendants("record")
                                                     where
                                                obj.Element("id").GetValue().XMLContains(valueToSearch) || ...
    

    【讨论】:

      【解决方案2】:

      您收到 NullReferenceException 是因为您尝试访问每个 record 不存在的某些节点的值,例如 specs。调用.Value之前需要检查是否obj.Element("specs") != null

      您也可以使用 XPath:

      var doc = XDocument.Load("test.xml");
      var records = doc.XPathSelectElements("//record[contains(id, '2') or contains(name, 'test') or contains(resume, 'res') or contains(specs, 'spe')]");
      

      【讨论】:

        【解决方案3】:

        首先我很惊讶它没有崩溃,因为您没有使用命名空间。也许 c#4.0 绕过了这个?

        随便试试

        obj.Descendants("id").Any() ? root.Element("id").Value : null
        

        即:

        select new ProductRecord {
            ID = obj.Descendants("id").Any() ? root.Element("id").Value : null,
            Name = obj.Descendants("name").Any() ? root.Element("name").Value : null,
            Resume = obj.Descendants("resume").Any() ? root.Element("resume").Value : null
            Specs = obj.Descendants("specs").Any() ? root.Element("specs").Value : null
        };
        

        【讨论】:

        • 问题不在选择中,我用这段代码绕过了这个 Specs = (string)obj.Element("Specs") ?? “不适用”。主要问题在于where子句...
        • 尝试使用相同的逻辑? (字符串)obj.Element(“规格”)??真的。就好像该对象不存在一样,您希望将其作为该记录的真正选项。