Запросы со сложной фильтрацией LINQ to XML c #

Я хочу понять сложную фильтрацию с помощью 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

Но я хочу отфильтровать более одного атрибута.

  1. Если я попытаюсь отфильтровать эти строки:

    (строка) add.Attribute ("LanguageId") == "английский" && (строка) add.Attribute ("LanguageId") == "испанский"

Почему не работает?

  1. Как я могу также отфильтровать "DialectsId"?

Пример: я хочу получить "Нью-Йорк" именно с такой фильтрацией:

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

Может у кого-то есть хороший исходник для сложной фильтрации? Я нашел этот https://docs.microsoft.com/de-de/dotnet/standard/linq/write-queries-complex-filtering, но это помогло мне лишь частично ...

# linq syntax
Источник
  • 1
    IMO создает классы, которые представляют структуру xml, затем десериализует новые классы и, наконец, использует linq для фильтрации и т. Д.
  • 0
    сделать условие ИЛИ. его же элемент. (строка) add.Attribute ("LanguageId") == "english" || (строка) add.Attribute ("LanguageId") == "испанский". запрошенная логика q может быть: ((строка) add.Attribute ("LanguageId") == "english" || (строка) add.Attribute ("LanguageId") == "испанский") || ((строка) add.Attribute ("DialectsId") == "запад" || (строка) add.Attribute ("DialectsId") == "cental")
  • 0
    @Aleksej, чтобы десериализовать xml в объект CLR, см. Другой вопрос: stackoverflow.com/questions/364253/…
  • 0
    Хорошо спасибо. Я постараюсь. Если найду решение, опубликую здесь.
  • 1
    DialectsId для испанского - «центральный» по отношению к Нью-Йорку и «центральный» по отношению к Лондону. Эта разница нужна?
Codelisting
за 2 против
Лучший ответ

я использовалAll вместо тогоAny так что он фильтрует только те города, которые удовлетворяют всем условиям. Я привык писать LINQ Expressions вместо LINQ Query.

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();
  • 0
    Я не забыл просьбу. :) Выглядит очень хорошо. Я проанализирую синтаксис, чтобы узнать больше. Если у меня будет другое решение, я сообщу всем.
за 1 против

Сначала см. Комментарий @zaggler. Десериализовать объект и управлять им станет проще.

Во-вторых, если вам нужны города, в которых говорят только на английском и испанском, см. Ответ @AkshayGaonkar. Если вам нужны города, в которых говорят на английском и испанском (а может, и на других языках), см. Мой ответ.


Чтобы написать сложный запрос Linq, я начинаю писать simulacrum 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;

Может быть, это не лучший трюк, но иногда может помочь.

  • 0
    @AkshayGaonkar, спасибо. central или cental , это звучит как ошибка в вопросе.
  • 0
    Что ж, это меняет весь сценарий. Я использовал All чтобы выводить New York Если Лондон также является допустимым выходом, мне нужно перейти на Any
Codelisting
Популярные категории
На заметку программисту