基于属性 name/value 对创建通用 xml linq 搜索

Creating a generic xml linq search based on attribute name/value pairs

我有一组正在处理的函数,其中一个是解析 XML 文件,return 与我创建的基于属性的条件相匹配的元素有。

这是 XML 我必须使用的示例:

 <rs:insert>
<z:row Inst='AM5001' Event='EventA' HostName='HostA' EventType='NORMAL' TXID='0000003327'/>
<z:row Inst='AM5001' Event='EventB' HostName='HostB' EventType='NORMAL' TXID='0000011173'/>
<z:row Inst='AM4067' Event='EventA' HostName='HostA' EventType='NORMAL' TXID='0000011175'/>
<z:row Inst='AM5546' Event='EventC' HostName='HostC' EventType='NORMAL' TXID='0000011177'/>
<z:row Inst='AM4567' Event='EventQ' HostName='HostD' EventType='NORMAL' TXID='0000011593'/>

这是我目前得到的片段:

internal protected IEnumerable<XElement> GetElement(XDocument oXMLDoc
        , List<KeyValuePair<string, string>> SearchCriteria)
    {
        var vElementQuery = oXMLDoc.Elements()
            .Where(e => SearchCriteria.ForEach(sc => e.Attribute(sc.Key).Value.ToUpper() == sc.Value.ToUpper()))
            .Select(e => e);

        foreach (var xElement in vElementQuery)
        {
            yield return xElement;
        }
    }

我在 vElementQuery 的 where 子句中遇到错误:

Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement

简单来说,我会基于 Inst 和 Event 进行查询,但偶尔我也需要基于主机名和 Eventtype。

基本上,我不知道我需要匹配多少个属性条件,所以我想将它们添加为列表或数组,认为 KeyValuePair 会很有用,因为它给我所需的名称和比较(值)。

感谢您的帮助。

Where 需要一个谓词:一个接受 e(本例中为 XElement)和 return 为 bool 的函数。

相反,您正在尝试 return SearchCriteria.ForEach() 的结果,return 是 void。它所做的只是遍历集合并为每个项目调用 void lambda。所以你不能将它用作谓词的主体。这将是您修复此问题后的下一个问题,但同一个修复可以同时解决这两个问题。

.Where(e => 
    SearchCriteria.ForEach(sc => 
        e.Attribute(sc.Key).Value.ToUpper() == sc.Value.ToUpper()
    )
)

因为ForEach returns void,它需要一个lambda returns void。函数体必须是语句。在 lambda 中,如果 return 类型不是 void,并且正文是一个表达式,则该表达式的结果是 returned —— 称它为隐式 return 陈述。但是这里的 return 值是无效的——这是由 the parameter type of ForEach:

建立的
public void ForEach(
    Action<T> action
)

Action<T> 有一个参数,没有 return 类型。编译器使用的任何推理规则都会导致它假设您正在尝试编写一个 void lambda,而不是您正在尝试给 ForEach 一个谓词。

这是您提供的 lambda 的主体:

e.Attribute(sc.Key).Value.ToUpper() == sc.Value.ToUpper()

如果编译器没有在它前面提供一个隐式的 return,那不是一个语句。是一种表达。作为声明,它不是合法的 C#。尝试编译:

1 != 2;

同样的错误。 C 或 Perl 不关心,但 C# 关心。

我想你可能想要 Any 而不是 ForEach:

.Where(e => 
    SearchCriteria.Any(sc => 
        e.Attribute(sc.Key).Value.ToUpper() == sc.Value.ToUpper()
    )
)

也就是说,return 任何 e 其中任何搜索条件匹配其任何属性。 Any 采用谓词和 returns bool,修复了这两个错误。