Extract value of an element where an attribute equals a specific value
I'm stumped yet again by XDocument. I'm trying to extract the value of the temperature element (12 in this example) when the class attribute has a value="high" (and "low")
A subset of my XML:
<forecastGroup>
<forecast>
<temperatures>
<textSummary>Low plus 2. High 12.</textSummary>
<temperature unitType="metric" units="C" class="high">12</temperature>
<temperature unitType="metric" units="C" class="low">2</temperature>
</temperatures>
</forecast>
...etc.
<forecast>
<temperature unitType="metric" units="C" class="high">15</temperature>
<temperature unitType="metric" units="C" class="low">3</temperature>
</forecast>
<forecastGroup>
Code so far:
XDocument loaded = XDocument.Parse(strInputXML);
foreach (var forecast in loaded.Descendants("forecastGroup").Elements("forecast"))
{
//existing code doing stuff here using the XDocument loaded
High开发者_运维问答 = "this is where I'm lost";
}
I've seemingly tried every combinations of trying to select Elements, Attributes, and Descendants", but I'm at a loss.
You can just add a Where()
filter to your Linq to XML query:
XDocument loaded = XDocument.Parse(strInputXML);
var matchingForecasts = loaded.Descendants("temperature")
.Where(x => (string)x.Attribute("class") == "high");
foreach (var forecast in matchingForecasts)
{
//do something
string temperature = forecast.Value;
}
Alternatively you could look at each class
attribute value within the foreach
loop, which is closer to your original approach:
foreach (var forecast in loaded.Descendants("temperature"))
{
//existing code doing stuff here using the XDocument loaded
if (forecast.Attribute("class").Value == "high")
{
//do something
string temperature = forecast.Value;
}
}
To extract the high inside your loop, you could use the line
var high = (int)forecast.Element("temperatures")
.Elements("temperature")
.Where(temp => temp.Attribute("class").Value == "high")
.First();
Of course, you could use Linq-to-XML to simply project the entire XML tree into an appropriate object graph without explicitly taking it apart in a loop, but you should be able to progress your way towards that. It may end up looking something like
var forecasts = from forecast in loaded.Descendants("forecast")
let temps = forecast.Element("temperatures")
let high = temps.Elements("temperature").Where(t => t.Attribute("class").Value == "high").First()
let low = temps.Elements("temperature").Where(t => t.Attribute("class").Value == "low").First()
select new
{
Temperatures = new
{
Summary = temps.Element("textSummary").Value,
High = new
{
UnitType = high.Attribute("unitType").Value,
Units = high.Attribute("units").Value,
Value = (int)high
},
Low = new
{
UnitType = low.Attribute("unitType").Value,
Units = low.Attribute("units").Value,
Value = (int)low
},
}
};
loaded.Descendants("temperature")
.Where(d => d.Attribute("class").Value.Equals("high")).First().Value
The sample XML file will not work because it is not closed properly.
<forecastGroup>
<forecast>
<temperatures>
<textSummary>Low plus 2. High 12.</textSummary>
<temperature unitType="metric" units="C" class="high">12</temperature>
<temperature unitType="metric" units="C" class="low">2</temperature>
</temperatures>
</forecast>
...etc.
<forecast>
<temperature unitType="metric" units="C" class="high">15</temperature>
<temperature unitType="metric" units="C" class="low">3</temperature>
</forecast>
<forecastGroup> // <= this needs to be </forecastGroup>
You can try use XPath like this:
using System.Xml.XPath;
...
string xpathExpression = "forecastGroup/forecast//temperature[@class='high']";
foreach (XElement el in loaded.XPathSelectElements(xpathExpression))
{
int highTemperature = Int32.Parse(el.Value);
}
The search expression could be shorter ("//temperature[@class='high']"
), but it's more efficient to be more detailed about position of values.
If you want to filter temperatures with 'high' or 'low' class attribute value, you can use this xpath expression:
"forecastGroup/forecast//temperature[@class='high' or @class='low']"
If you want decide what to do, based on @class attribute, you can use this code:
string xpathExpression = "forecastGroup/forecast//temperature[@class='high' or @class='low']";
foreach (XElement el in loaded.XPathSelectElements(xpathExpression))
{
int temperature = Int32.Parse(el.Value);
if (el.Attribute("class").Value == "low")
{
// do sth with low value
}
else
{
// do sth with high value
}
}
精彩评论