2017-01-25 43 views
3

不知道我該如何做到這一點。c#使用XElement的元素元素

這裏是我的工作的XML:

<configuration> 
    <tag1> 
     <interestingstuff>avalue</interestingstuff> 
    </tag1> 

    <tag2> 
     <item_type1 name="foo"> 
      <item_type2 name="bar"> 
       <property>value1</property> 
       <property>value2</property> 
      </item_type2> 
      <item_type2 name="pub"> 
       <property>valueX</property> 
       <property>valyeY</property> 
      </item_type2> 
      <item_type1> 

      <item_type1 name="foo2"> 
       <item_type2 name="pub"> 
        <property>valueX</property> 
       </item_type2> 
      </item_type1> 
     </tag2> 
</configuration> 

我正在寫通行證ITEM_TYPE和item_type2值的函數,並返回屬性值的列表,以組合。

這是我的。它會在所指出的位置拋出一個「未設置爲對象實例的對象」異常。

ArrayList properties = new ArrayList(); 
XDocument config = new XDocument(); 
config = XDocument.Parse(XML_Text); 
foreach (XElement item1 in config.Root.Element("tag2").Nodes()) 
{ 
    if (item1.Attribute("name").Value.ToString() == passed_item1_value) 
    { 
     //this is where it's breaking 
     foreach (XElement item2 in item1.Elements("item_type2").Nodes()) 
     { 
     if item2.Attribute("name").Value.ToString() == passed_item2_value) 
     { 
      foreach (XElement property in item2.Elements("property").Nodes()) 
      { 
      properties.Add(property.Value.ToString()); 
      } 
      break; 
     } 
     } 
     break; 
    } 
} 

我知道這沒有任何意義 - 但我不能說得通。

+0

它是如何「破」的東西嗎?始終包含完整的錯誤消息。 –

+0

直接的答案是(我猜)XElement不能迭代Nodes()。但是下面的Linq答案要好得多。 –

+0

Breaking =「對象引用未設置爲對象的實例」異常。 這是預期的。我想出了Henk Holterman剛發佈的同樣的東西,我試圖迭代一個非迭代。但是當我試圖找到正確的方式時,我只是感到困惑。 –

回答

3

我會做這種方式:

public IEnumerable<string> findValues(string item1, string item2) 
{ 
    config = XDocument.Parse(XML_Text) 
    var res = config.Descendants("item_type1") 
        .Where(x=>x.Attribute("name").Value == item1) 
        .Descendants("item_type2") 
        .Where(x=>x.Attribute("name").Value == item2); 
    return res.Descendants("property").Select(x=>x.Value); 
} 
+0

看起來更優雅!忘記添加,但有可能數據可能不包含匹配節點(item_type1或item_type2)。這會打破這個解決方案嗎? –

+0

@GregorySloan你會得到空集合,但沒有例外 –

+2

只是旁註,但後代()忽略所有文檔結構。它也會找到一個''多個層次。這並不總是一個功能。 –

1

我想你想XPath查詢類似以下內容:

var path = string.Join("/", 
    "configuration", 
    "tag2", 
    string.Format("item_type1[@name='{0}']", passed_item1_value), 
    string.Format("item_type2[@name='{0}']", passed_item2_value), 
    "property"); 

var elements = (IEnumerable)config.XPathEvaluate(path); 

var properties = elements.Cast<XElement>().Select(x => x.Value); 

不要忘了包括using System.Xml.XPath;這裏定義XPathEvaluate

1
using System.Linq; 
using System.Xml.Linq; 

IEnumerable<string> GetProperties(XElement xml, string item1, string item2) 
{ 
    return xml.Element("tag2") 
     .Elements("item_type1").Where(x => x.Attribute("name").Value == item1) 
     .Elements("item_type2").Where(x => x.Attribute("name").Value == item2) 
     .SelectMany(x => x.Elements("property").Select(p => p.Value)); 
} 

許多上述方案類似,但採用的是直接的路徑數據,並使用SelectMany的結果轉變成一個單一的集合 - 即會工作,如果你有物品1的重複和ITEM2。

0

在情況下VB'er需要幫助與同類

Dim xe As XElement 
    xe = <configuration> 
      <tag1> 
       <interestingstuff>avalue</interestingstuff> 
      </tag1> 

      <tag2> 
       <item_type1 name="foo"> 
        <item_type2 name="bar"> 
         <property>value1</property> 
         <property>value2</property> 
        </item_type2> 
        <item_type2 name="pub"> 
         <property>valueX</property> 
         <property>valyeY</property> 
        </item_type2> 
       </item_type1> 

       <item_type1 name="foo2"> 
        <item_type2 name="pub"> 
         <property>valueX</property> 
        </item_type2> 
       </item_type1> 
      </tag2> 
     </configuration> 

    Dim passed_item1_value As String = "foo" 'for test 
    Dim passed_item2_value As String = "pub" 'for test 

    Dim ie As IEnumerable(Of String) 
    ie = (From el In xe.<tag2>.<item_type1>...<item_type2> 
      Where [email protected] = passed_item1_value AndAlso [email protected] = passed_item2_value 
      From sel In el...<property> Select sel.Value) 

    Return ie.ToArray