简体   繁体   English

包含 Linq 到 XML Where 子句中的功能

[英]Contains functionality in Linq to XML Where Clause

I'm having unexpected behavior with the.Contains() function of the where clause in Linq to XML.我在 Linq 到 XML 的 where 子句的It seems to be functioning like "==" not Contains() in the string function.它的功能似乎类似于字符串 function 中的“==”not Contains()。

Example:例子:

var q = from sr in SearchResults.Descendants("Result")
    where _filters.Contains((string)sr.Element("itemtype"))
    orderby (string)sr.Element("ipitemtype") ascending
    select new SearchItem
    {
        //Create Object
        ID = (string)sr.Element("blabla"),
    }

_filters is a list of strings. _filters 是一个字符串列表。 Let's say it contains 3 values:假设它包含 3 个值:

_filters[0] = "videos";
_filters[1] = "documents";
_filters[2] = "cat pictures";

What happens now, is that the Query works perfectly if现在发生的情况是,如果 Query 完美运行

<itemtype>videos</itemtype> 

is the XML node.是 XML 节点。

However, if the node is但是,如果节点是

<itemtype>videos mission critical document advertising</itemtype>, 

the IEnumerable returns blank, which to me says the operand is functioning like "==" not "Contains()". IEnumerable 返回空白,这对我来说说操作数的功能类似于“==”而不是“Contains()”。

Any idea what I'm doing wrong?知道我做错了什么吗?

Winning answer from dtb:来自 dtb 的获奖答案:

replace代替

where _filters.Contains((string)sr.Element("itemtype"))

with

where _filters.Any(filter => ((string)sr.Element("itemtype")).Contains(filter))

Try this:尝试这个:

_filters.Any(s => ((string)sr.Element("itemtype") ?? "").Contains(s))

This way you're checking that the element's value contains any of the strings in _filters .这样您就可以检查元素的值是否包含_filters中的任何字符串。 The use of the null coalescing operator ensures a NullReferenceException isn't thrown when the itemtype node doesn't exist since it is replaced with an empty string.使用 null 合并运算符可确保在itemtype节点不存在时不会引发NullReferenceException ,因为它被替换为空字符串。

The other approach is to use let and filter out the nulls:另一种方法是使用let并过滤掉空值:

var q = from sr in SearchResults.Descendants("Result")
        let itemtype = (string)sr.Element("itemtype")
        where itemtype != null &&
              _filters.Any(filter => itemtype.Contains(filter))
        orderby (string)sr.Element("ipitemtype") ascending
        select new SearchItem
        {
            //Create Object
            ID = (string)sr.Element("blabla")
        }

Note that String.Contains is case sensitive.请注意, String.Contains区分大小写。 So a check for "videos" won't match on "Videos" with a capital "V".因此,对“视频”的检查不会与带有大写字母“V”的“视频”匹配。 To ignore case you can use String.IndexOf in this manner:要忽略大小写,您可以使用String.IndexOf这种方式:

_filters.Any(filter => itemtype.IndexOf(filter, StringComparison.InvariantCultureIgnoreCase) >= 0)

You are checking if the array _filters has an element with the value "videos mission critial document advertising" (which is not the case), rather than if "videos mission critial document advertising" contains any of the elements in _filters .您正在检查数组_filters是否具有值为"videos mission critial document advertising"的元素(不是这种情况),而不是"videos mission critial document advertising"是否包含_filters中的任何元素。

Try this:尝试这个:

where _filters.Any(filter => ((string)sr.Element("itemtype")).Contains(filter))

The problem is that you are making false assumptions about the way the Contains method works.问题是您对Contains方法的工作方式做出了错误的假设。 (Also see the String.Contains() documentation The contains method returns true if "a sequence contains a specific element". In the example you described, both the _filters array and the itemtype text contains the string videos , but neither contain each other. A more appropriate test would be to use the following extension method: (另请参阅String.Contains()文档如果“序列包含特定元素”,则 contains 方法返回 true。在您描述的示例中, _filters数组和itemtype文本都包含字符串videos ,但彼此都不包含。更合适的测试是使用以下扩展方法:

public static class ContainsAnyExtension
{
    public static bool ContainsAny<T>(this IEnumerable<T> enumerable, params T[] elements)
    {
        if(enumerable == null) throw new ArgumentNullException("enumerable");
        if(!enumerable.Any() || elements.Length == 0) return false;
        foreach(var element in elements){
           if(enumerable.Contains(element)){
               return true;
           }
        }
        return false;
    }
}

So, your correct LINQ query would be:因此,您正确的 LINQ 查询将是:

var q = from sr in SearchResults.Descendants("Result")
        where ((string)sr.Element("itemtype")).ContainsAny(_filters)
        orderby ((string)sr.Element("ipitemtype")) ascending
        select new SearchItem
        {
            ID = sr.Element("blabla").Value
        };

It may also be helpful to review this post: How do I use LINQ Contains(string[]) instead of Contains(string) , which is similar but specifically targets the String.Contains method instead of the Enumerable.Contains extension.查看这篇文章也可能会有所帮助: 我如何使用 LINQ Contains(string[]) 而不是 Contains(string) ,它类似但专门针对String.Contains方法而不是Enumerable.Contains扩展。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM