开发者

How to get an element from a node in XDocument where two other elements are known

I'm stumped (again) with an misunderstanding of XDocument/Linq. For the XML below, I have nameEn and provinceCode as variables in my code. I'm trying to identify the code (e.g., s0000002) and nameFr given I have the other two elements. The provinceCode and NameEn combined are unique in the XML (no duplication).

<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>

Here's the code I'm trying (my XML is in the "loaded" XDocument:

selectedProvince = "ON";
selectedCity = "Algonquin Park"开发者_StackOverflow中文版;      
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();

The string strSiteCode returns: System.Linq.Enumerable+WhereSelectEnumerableIterator2[System.Xml.Linq.XElement,System.String]andstrNameFRreturns""`.

I can't figure out what the working code should look like. Thanks for any help.

Doug


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();
}

The Select() call returns a collection (which, in your case happens to have just one element). So you'll have to call SingleOrDefault() (or Single() ) to get the one item. Also, I removed the second Where() and included the condition to the first Where().


Keep in mind that it's possible that the "x.Element(...)" method will return null, whereby accessing "Value" on it will cause a null ref. This is assuming that your xml may not always have the provinceCode or nameEn. If it does, you won't have a problem, but you wouldn't want to put that possible null ref ex in release code, anyways. The following solves the null ref problem.

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");


I would probably rewrite it like this:

  • get the list of matching <site> nodes once
  • iterate over all matches (typically only one)
  • get the code attribute and nameFr element from those matching items

Code would look like this:

// 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;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜