Расширение C # где метод - обработка случая, когда элемент не найден - PullRequest
1 голос
/ 13 февраля 2010

Я пытаюсь запросить этот очень сложный XML-документ, используя xDocument и LINQ to XML . Я хочу выполнить следующее действие:

Получить все элементы, которые соответствуют определенным критериям, а если нет, вернуть другой атрибут из xDocument.

Пример:

<cars>
    <car>
        <patrol type="oil">
            <url> http://Toyotaoil.com </url>
        </patrol>
    </car>
    <car>
        <patrol type="oil">
            <url> http://BMWoil.com </url>
        </patrol>
        <patrol type="gas">
            <url> http://BMWgas.com </url>
        </patrol>
    </car>
    <car>
        <patrol type="gas">
            <url> http://Hondagas.com </url>
        </patrol>
    </car>

Теперь, что я хотел бы получить из этого запроса, это список патрулей типа масла, если только автомобиль не использует бензин, и тогда я был бы доволен газом.

Если я использую предложение where, я просто пропускаю случаи, когда автомобиль использует газ. Есть ли такая вещь, как предложение where, где я могу указать, что делать, если они не выполняются?

Ответы [ 6 ]

2 голосов
/ 13 февраля 2010

Решение, представленное ниже, должно дать вам гибкость в запросе того, что вам нравится:

var result = from car in xdoc.Element("cars").Elements("car") 
             let patrols = car.Elements("patrol")
             let oils = patrols.Where(patrol => patrol.Attribute("type") == "oil")
             select new {
                    Car = car,
                    Patrols = (oils.Any() ? oils : patrols)
             }

У меня нет Visual Studio здесь, поэтому я надеюсь, что он компилируется:)
Дайте немного больше информации о том, что вы хотели бы выбрать, и я дам вам более конкретную инструкцию LINQ.

2 голосов
/ 13 февраля 2010
xdoc.Element("cars")
    .Elements("car")
    .Select(car => car.Elements("patrol")
                      .SingleOrDefault(p => (string)p.Attribute("type") == "oil")
                   ??
                   car.Elements("patrol")
                      .Single(p => (string)p.Attribute("type") == "gas"));
1 голос
/ 13 февраля 2010

Вы можете просто сделать что-то вроде этого:

var query = from element in someElements
            select element.Attribute("type").Value == "oil"
                ? returnSomethingWhenItIsOil
                : returnSomethingWhenItIsSomethingElse;

или

var query = from element in someElements
            where element.Attribute("type") == "oil"
                || element.Attribute("type") == "gas"
            select element;

Но объясните проблему лучше, спасибо:)

0 голосов
/ 13 февраля 2010
                       var cars = from c in xdoc.Descendants("car")
                       where
                       (c.Element("patrol").Attribute("type").Value == "oil" ||
                       c.Element("patrol").Attribute("type").Value == "gas")
                       select new Car
                       {
                           FuelType = c.Element("patrol").Attribute("type").Value.ToString()
                       };

    foreach (Car c in cars)
        {
            Console.WriteLine(c.ToString());
        }

    class Car
    {
        public string FuelType { get; set; }
        public override string ToString()
        {
            return "Car FeulType = " + this.FuelType.ToString();
        }
    }

Это результаты, которые я получаю

alt text http://img694.imageshack.us/img694/5016/carse.jpg

0 голосов
/ 13 февраля 2010

Звучит так, будто вам вообще не нужно предложение where - вам просто нужно предложение select, которое выбирает одно или другое значение.

Тем не менее, ваш пример не описывает, как бы вы выбрали другой элемент на основе значений - какой «другой атрибут» вы бы выбрали? Что вы подразумеваете под "где автомобиль использует газ"? Если вы можете дать более подробную информацию о примере, вам не составит труда дать вам соответствующий код.

0 голосов
/ 13 февраля 2010

Order по типу в соответствии с вашими требованиями, возьмите FirstOrDefault().


Редактировать: я имел в виду что-то вроде этого:

var patrols = from car in doc.Root.Elements()
              let p = car.Elements().OrderBy(patrol=>patrol.Attribute("type").Value).First()
              select p;

Возвращает один результат на машину. Проверьте предложение OrderBy и измените его соответствующим образом. Это приведет к:

<patrol type="oil">
  <url> http://Toyotaoil.com </url>
</patrol>

<patrol type="gas">
  <url> http://BMWgas.com </url>
</patrol>

<patrol type="gas">
  <url> http://Hondagas.com </url>
</patrol>

Снова отредактируйте: ах, теперь щелкнуло. Да, это возвращает только один элемент на машину - Zyphrax дал хорошее решение.

...