Извлечь значение элемента, где атрибут равен определенному значению - PullRequest
0 голосов
/ 07 октября 2011

Я снова в тупике от XDocument. Я пытаюсь извлечь значение элемента температуры (12 в этом примере), когда атрибут класса имеет значение = "высокий" (и "низкий")

Подмножество моего 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>

Код пока:

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

Я, похоже, перепробовал все комбинации, пытаясь выбрать элементы, атрибуты и потомки ", но я в растерянности.

Ответы [ 5 ]

2 голосов
/ 07 октября 2011

Вы можете просто добавить фильтр Where() к вашему запросу Linq to XML:

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

В качестве альтернативы вы можете посмотреть каждое значение атрибута class в цикле foreach, которое ближе к вашему первоначальному подходу:

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;
    }
}
1 голос
/ 16 февраля 2015

Пример 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>   // <= this needs to be </forecastGroup>
1 голос
/ 07 октября 2011

Чтобы извлечь максимум из вашего цикла, вы можете использовать строку

var high = (int)forecast.Element("temperatures")
                        .Elements("temperature")
                        .Where(temp => temp.Attribute("class").Value == "high")
                        .First();

Конечно, вы можете использовать Linq-to-XML, чтобы просто спроецировать все дерево XML в соответствующий граф объектов без явногоразбивая его на части, но вы должны быть в состоянии продвинуться к этому.Может получиться что-то вроде

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
                        },
                    }
                };
1 голос
/ 07 октября 2011
loaded.Descendants("temperature")
.Where(d => d.Attribute("class").Value.Equals("high")).First().Value
0 голосов
/ 07 октября 2011

Вы можете попробовать использовать XPath следующим образом:

using System.Xml.XPath;
...
string xpathExpression = "forecastGroup/forecast//temperature[@class='high']";
foreach (XElement el in loaded.XPathSelectElements(xpathExpression))
{
    int highTemperature = Int32.Parse(el.Value);
}

Выражение поиска может быть короче ("//temperature[@class='high']"), но более эффективно быть более подробным о положении значений.

Если вы хотите отфильтровать температуры с помощью значения атрибута класса 'high' или 'low', вы можете использовать это выражение xpath:

"forecastGroup/forecast//temperature[@class='high' or @class='low']"

Если вы хотите решить, что делать, основываясь на атрибуте @class, выможете использовать этот код:

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