Как получить элемент из узла в XDocument, где известны два других элемента - PullRequest
1 голос
/ 01 октября 2011

Я озадачен (снова) неправильным пониманием XDocument / Linq.Для приведенного ниже XML у меня есть nameEn и provinceCode в качестве переменных в моем коде.Я пытаюсь определить code (например, s0000002) и nameFr, учитывая, что у меня есть два других элемента.Объединенные provinceCode и NameEn уникальны в XML (без дублирования).

<siteList>
  <site code="s0000001">
    <nameEn>Edmonton</nameEn>
    <nameFr>Edmonton</nameFr>
    <provinceCode>AB</provinceCode>
  </site>
  <site code="s0000002">
    <nameEn>Algonquin Park</nameEn>
    <nameFr>Parc Algonquin</nameFr>
    <provinceCode>ON</provinceCode>
  </site>
...
</siteList>

Вот код, который я пытаюсь (мой XML находится в «загруженном» XDocument:

selectedProvince = "ON";
selectedCity = "Algonquin Park";      
strSiteCode = loaded.Descendants("site")
    .Where(x => x.Element("provinceCode").Value == selectedProvince)
    .Where(x => x.Element("nameEn").Value == selectedCity)
    .Select(x => x.Element("code").Value)
    .ToString();
strNameFR = loaded.Descendants("site")
    .Where(x => x.Element("provinceCode").Value == selectedProvince)
    .Where (x => x.Element("nameEn").Value == selectedCity)
    .Select(x => x.Element("nameFr").Value)
    .ToString();

Строка strSiteCode возвращает: System.Linq.Enumerable+WhereSelectEnumerableIterator 2 [System.Xml.Linq.XElement, System.String] and strNameFR returns "" `.

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

Дуг

Ответы [ 3 ]

1 голос
/ 02 октября 2011

Имейте в виду, что вполне возможно, что метод "x.Element (...)" вернет значение null, в результате чего доступ к значению Value приведет к нулевому значению ref.Это предполагает, что ваш xml не может всегда иметь провинциальный код или nameEn.Если это произойдет, у вас не возникнет проблем, но вы все равно не захотите поместить этот возможный нулевой ref ex в код релиза.Следующее решает проблему нулевых ссылок.

var site = loaded
    .Descendants("site")
    .FirstOrDefault(x => (string)x.Element("provinceCode") == selectedProvince &&
                    x => (string)x.Element("nameEn") == selectedCity);    

if (site == null)
{
    return
}

var siteCode = (string)site.Attribute("code");
var nameFr = (string)site.Element("nameFr");
1 голос
/ 01 октября 2011

Try

var result = loaded.Descendants("site")
    .Where(x => (x.Element("provinceCode").Value == selectedProvince) &&
                 (x.Element("nameEn").Value == selectedCity) )
    .Select(x => x.Element("code").Value)
    .SingleOrDefault();

if (result != null)
{
    strSiteCode = result.ToString();
}

Вызов Select() возвращает коллекцию (которая, в вашем случае, имеет только один элемент).Поэтому вам нужно позвонить SingleOrDefault() (или Single()), чтобы получить один предмет.Также я удалил вторую Where() и включил условие в первую Where().

0 голосов
/ 02 октября 2011

Я, вероятно, переписал бы это так:

  • получить список совпадающих <site> узлов за один раз
  • итерировать по всем совпадениям (обычно только по одному)
  • получить атрибут code и nameFr из соответствующих элементов

Код будет выглядеть следующим образом:

// determine the matching list of <site> nodes ...
var selectedSites = loaded
                       .Descendants("site")
                       .Where(x => x.Element("provinceCode").Value == selectedProvince)
                       .Where(x => x.Element("nameEn").Value == selectedCity);

// iterate over all matching <site> nodes
foreach (var site in selectedSites)
{
    // grab the code attribute and nameFr element from <site> node
    var siteCode = site.Attribute("code").Value;
    var nameFR = site.Element("nameFr").Value;
}
...