具有复杂过滤 LINQ to XML c# 的查询

Posted

技术标签:

【中文标题】具有复杂过滤 LINQ to XML c# 的查询【英文标题】:Queries with complex filtering LINQ to XML c# 【发布时间】:2021-08-21 13:45:07 【问题描述】:

我想了解使用 LINQ XML 进行的复杂过滤。 我创建了一个简单的 XML 示例(DataBaseCities.xml):

<?xml version="1.0" encoding="utf-8"?>
<DataBase>
    <DocumentInfo version="1.0" schemaVersion="1.0"/>
    <ListOfMegaCities>
        <MegaCities city="Moscow" continent="Europe">
            <VariantConstraint>
                <LanguageRef LanguageId="russian">
                    <LanguageDialectsRef DialectsId="north"/>
                </LanguageRef>
            </VariantConstraint>
            <Districts>                
                <CityDistrict District="Arbat"/>
                <CityDistrict District="Basmanny"/>
            </Districts>
        </MegaCities>
        <MegaCities city="New York" continent="North America">
            <VariantConstraint>
                <LanguageRef LanguageId="english">
                    <LanguageDialectsRef DialectsId="west"/>
                </LanguageRef>
                <LanguageRef LanguageId="spanish">
                    <LanguageDialectsRef DialectsId="cental"/>
                </LanguageRef>              
            </VariantConstraint>
            <Districts>                
                <CityDistrict District="Queens"/>
                <CityDistrict District="Bronx"/>
            </Districts>
        </MegaCities>
        <MegaCities city="London" continent="Europe">
            <VariantConstraint>
                <LanguageRef LanguageId="english">
                    <LanguageDialectsRef DialectsId="west"/>
                </LanguageRef>
                <LanguageRef LanguageId="spanish">
                    <LanguageDialectsRef DialectsId="central"/>
                </LanguageRef>  
                <LanguageRef LanguageId="french">
                    <LanguageDialectsRef DialectsId="central"/>
                </LanguageRef>              
            </VariantConstraint>
            <Districts>                
                <CityDistrict District="Greenwich"/>
                <CityDistrict District="Westminster"/>
            </Districts>
        </MegaCities>       
    </ListOfMegaCities>
</DataBase>

我尝试过滤如下:

        XElement root = XElement.Load(@"DataBaseCities.xml");
        IEnumerable<XElement> ListOfMegaCities =
            from el in root.Descendants("MegaCities")
            where
                (from add in el.Descendants("LanguageRef")
                 where
                      (string)add.Attribute("LanguageId") == "english"
                 select add)
            .Any()
            select el;

        foreach (XElement el in ListOfMegaCities)
        
            Console.WriteLine((string)el.Attribute("city"));
        

所以输出是:

New York
London

但我想过滤多个属性。

    如果我尝试使用这些行进行过滤:

    (string)add.Attribute("LanguageId") == "english" && (string)add.Attribute("LanguageId") == "西班牙语"

为什么它不起作用?

    如何过滤“方言 ID”?

示例:我想通过这个过滤得到“纽约”:

LanguageId="english"
DialectsId="west"
LanguageId="spanish"
DialectsId="cental"

也许有人有一个很好的复杂过滤来源?我找到了这个https://docs.microsoft.com/de-de/dotnet/standard/linq/write-queries-complex-filtering,但这只是部分帮助了我......

【问题讨论】:

IMO 创建代表 xml 结构的类,然后反序列化为新类,最后使用 linq 过滤等。 建立或条件。它的相同元素。 (string)add.Attribute("LanguageId") == "english" || (string)add.Attribute("LanguageId") == "西班牙语"。您请求的逻辑应该是: ((string)add.Attribute("LanguageId") == "english" || (string)add.Attribute("LanguageId") == "spanish") || ((string)add.Attribute("DialectsId") == "west" || (string)add.Attribute("DialectsId") == "cental") @Aleksej,要将 xml 反序列化为 CLR 对象,请参阅另一个问题:***.com/questions/364253/… 好的,谢谢。我会尝试。如果我找到解决方案,我会在这里发布。 西班牙语的 dialectsId 是纽约的“中部”和伦敦的“中部”。想要这种差异? 【参考方案1】:

首先,请参阅@zaggler 评论。反序列化和操作对象会更容易。

其次,如果您想要只说英语和西班牙语的城市,请参阅@AkshayGaonkar 答案。如果您想要使用英语和西班牙语(可能还有其他语言)的城市,请参阅我的回答。


为了写复杂的Linq查询,我开始写模拟SQL:

-- I want all cities
select * from MegaCities as el
where
    -- that speak english with west dialect
    exists (
        select * from el.LanguageRef as add
        where add.LanguageId = 'english' and
            add.LanguageDialectsRef.DialectsId = 'west'
    )
    -- and also speak spanish with central dialect
    and exists (
        select * from el.LanguageRef as add
        where add.LanguageId == 'spanish' and
            add.LanguageDialectsRef.DialectsId = 'cental'
    )

然后我可以转置到 Linq :

IEnumerable<XElement> ListOfMegaCities =
    from el in root.Descendants("MegaCities")
    where
        (from add in el.Descendants("LanguageRef")
         where add.Attribute("LanguageId").Value == "english" &&
            add.Element("LanguageDialectsRef").Attribute("DialectsId").Value == "west"
         select add)
        .Any()
        &&
        (from add in el.Descendants("LanguageRef")
         where add.Attribute("LanguageId").Value == "spanish" &&
            add.Element("LanguageDialectsRef").Attribute("DialectsId").Value == "cental"
         select add)
        .Any()
    select el;

也许不是最好的技巧,但有时会有所帮助。

【讨论】:

@AkshayGaonkar,谢谢。 centralcental,这听起来像是问题中的错误。 嗯,这改变了整个场景。我曾使用All 专门将New York 作为输出。如果 London 也是有效输出,那么我必须更改为 Any【参考方案2】:

我使用了All 而不是Any,因此它只过滤那些满足所有条件的城市。我习惯于编写 LINQ 表达式而不是 LINQ 查询。

List<XElement> ListOfMegaCities = root.Descendants("MegaCities")
                                 .Where(lr => lr.Descendants("LanguageRef")
                                 .All(
                                      li => (li.Attribute("LanguageId").Value == "english" 
                                          && li.Element("LanguageDialectsRef").Attribute("DialectsId").Value == "west")
                                          || (li.Attribute("LanguageId").Value == "spanish" 
                                          && li.Element("LanguageDialectsRef").Attribute("DialectsId").Value == "cental")
                                            )                                     
                                 ).ToList();

【讨论】:

我没有忘记请求。 :) 这看起来非常好。我将分析语法以了解更多信息。如果我有其他解决方案,我会告诉大家。

以上是关于具有复杂过滤 LINQ to XML c# 的查询的主要内容,如果未能解决你的问题,请参考以下文章

具有 Lightswitch 计算属性的 Linq to SQL 查询过滤器

C#中的Linq to Xml详解

Linq to Xml C#在特定元素中查找特定元素

在 C# 中使用 Linq to XML 在文档中搜索不同的 XML 结构

检查 XML 节点是不是具有 Linq C# 的属性?

Linq to XML 增删改查