2011-10-06 70 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> 
相關問題