2017-01-25 2 views
3

どうすればよいか分かりません。c#XElementを使用する要素の要素

ここで私が働いているXMLです:私はITEM_TYPEとitem_type2の値を渡し、その組み合わせのプロパティ値のリストを返す関数を書いて

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

が。

ここに私のものがあります。それは "オブジェクトのインスタンスに設定されていないオブジェクト"の例外を、その時点でスローします。

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がノード()上で反復できないことです(おそらく)。しかし、以下の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

Descendants()はすべてのドキュメント構造を無視します。また、 ''のレベルが下がっています。それは必ずしも機能ではありません。 –

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を使用しています - あなたはITEM1と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 
関連する問題