2017-01-25 47 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