2011-10-06 68 views
0

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

我貌似试过的尝试,选择每一个元素的组合,属性和子孙”,但我在亏损

+1

如果你愿意,'XPath'会更容易。 – Marc

回答

1

要提取你的循环里面的高度,你可以用这条线

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 
         }, 
        } 
       }; 
+0

谢谢!这很好(代码的第一位)。我也只注意到有时高属性不存在。我似乎得到一个空引用错误。我尝试添加更改“.First();”到“.First()?? String.Empty;”但那是行不通的。如何避免这样的错误? – Doug

+0

@Doug,FirstOrDefault()将返回第一个元素(如果存在),或者返回类型的默认值(对于类,则为null)。你会希望在使用结果之前检查null(在我的例子中为cast)。或者你可以投到'int?'而不是'int',它可以很好地处理null。 –

+0

'var high =(int?)预测./*内部的东西被省略* /。FirstOrDefault();' –

1

你可以只添加一个。过滤器,你的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; 
} 

另外,您可以看看foreach循环,这是更接近你原来的做法中的每个class属性值:

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
loaded.Descendants("temperature") 
.Where(d => d.Attribute("class").Value.Equals("high")).First().Value 
0

您可以尝试使用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']"),但它是更有效的是有关位置的更详细值。

如果要过滤下具有“高”或“低”类属性值,您可以使用此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 
    } 
} 
1

示例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> 
相关问题