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+WhereSelectEnumerableIterator
2[System.Xml.Linq.XElement,System.String]and
strNameFRreturns
""`.
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 andnameFr
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;
}
精彩评论