如何按属性选择XML节点并使用它的子节点数据

本文关键字:子节点 数据 属性 何按 选择 XML 节点 | 更新日期: 2023-09-27 17:49:29

这是我的XML文件

<?xml version="1.0" encoding="utf-8" ?> 
<storage>   
<Save Name ="Lifeline">
 <Seconds>12</Seconds>
 <Minutes>24</Minutes>
 <Hours>9</Hours>
 <Days>25</Days>
 <Months>8</Months>
 <Years>2010</Years>
 <Health>90</Health>
 <Mood>100</Mood>  
</Save> 
<Save Name ="Hellcode">   
 <Seconds>24</Seconds>
 <Minutes>48</Minutes> 
 <Hours>18</Hours>
 <Days>15</Days>
 <Months>4</Months>
 <Years>1995</Years>
 <Health>50</Health>
 <Mood>50</Mood>  
</Save> 

这是一个从XML中获取数据并将其加载到应用程序的代码。

System.IO.StreamReader sr = new System.IO.StreamReader(@"Saves.xml");
System.Xml.XmlTextReader xr = new System.Xml.XmlTextReader(sr);
System.Xml.XmlDocument save = new System.Xml.XmlDocument();
save.Load(xr);

XmlNodeList saveItems = save.SelectNodes("Storage/Save");
XmlNode seconds = saveItems.Item(0).SelectSingleNode("Seconds");
sec = Int32.Parse(seconds.InnerText);
XmlNode minutes = saveItems.Item(0).SelectSingleNode("Minutes");
min = Int32.Parse(minutes.InnerText);
XmlNode hours = saveItems.Item(0).SelectSingleNode("Hours");
hour = Int32.Parse(hours.InnerText);
XmlNode days = saveItems.Item(0).SelectSingleNode("Days");
day = Int32.Parse(days.InnerText);
XmlNode months = saveItems.Item(0).SelectSingleNode("Months");
month = Int32.Parse(months.InnerText);
XmlNode years = saveItems.Item(0).SelectSingleNode("Years");
year = Int32.Parse(years.InnerText);
XmlNode health_ = saveItems.Item(0).SelectSingleNode("Health");
health = Int32.Parse(health_.InnerText);
XmlNode mood_ = saveItems.Item(0).SelectSingleNode("Mood");
mood = Int32.Parse(mood_.InnerText);

问题是这段代码直接从"生命线"节点加载数据。我想使用一个列表框,并能够选择从哪个节点加载数据。

我已经尝试从列表框项目内容的字符串,然后使用这样的行

XmlNodeList saveItems = save.SelectNodes(string.Format("storage/Save[@Name = '{0}']", name)); 

变量"name"是来自列表框项的字符串。在编译时,此代码给出异常。有人知道如何按属性选择并从XML中加载所需数据吗?

如何按属性选择XML节点并使用它的子节点数据

如果可以使用XElement:

XElement xml = XElement.Load(file);
XElement storage = xml.Element("storage");
XElement save = storage.Elements("Save").FirstOrDefault(e => ((string)e.Attribute("Name")) == nameWeWant);
if(null != save) 
{
// do something with it
}

我个人喜欢那些具有属性的类,这些属性可以转换为XElement,从而对主程序隐藏细节。IE说Save类在构造函数中接受一个XElement节点,在内部全局保存它,并读取/写入它的属性。

示例类:

  public class MyClass
    {
      XElement self;
      public MyClass(XElement self)
      {
         this.self = self;
      }
    public string Name
    {
      get { return (string)(self.Attribute("Name") ?? "some default value/null"); }
      set 
      { 
        XAttribute x = source.Attribute("Name");
        if(null == x)
          source.Add(new XAttribute("Name", value));
        else
          x.ReplaceWith(new XAttribute("Name", value));
      }
    }
   }

然后你可以把搜索改成:

XElement save = storage.Elements("Save")
    .FirstOrDefault(e => new MyClass(e).Name == NameWeWant);

由于它不是那么多的数据,我建议将所有信息加载到保存(构造函数)的列表中,然后从那里绘制用户想要使用的…

至于不工作的东西,我个人使用较低级别的方法来获取我的数据,它不容易出错。重塑它以适应你的问题:

int saves = 0;
List<Saves> saveGames = new List<Saves>();
saveGames.Add(new Saves());
while (textReader.Read())
{
   if (textReader.NodeType == XmlNodeType.Element)
      whatsNext = textReader.Name;
   else if (textReader.NodeType == XmlNodeType.Text)
   {
      if (whatsNext == "name")
         saveGames[saves].name = Convert.ToString(textReader.Value);
      //else if statements for the rest of your attributes
      else if (whatsNext == "Save")
      {
         saveGames.Add(new Saves());
         saves++;
      }
   }
   else if (textReader.NodeType == XmlNodeType.EndElement)
      whatsNext = "";
}

基本上将xml文件中的所有内容放入对象列表中,并操作该列表以填充列表框。使用一个name属性作为保存的第一个属性,而不是save name = "…"。

代码标签讨厌我。

选择节点返回两个XmlNode对象。

XmlNodeList saveItems = save.SelectNodes("Storage/Save");

稍后在您的代码中,您似乎选择了第一个,并使用saveItems.Item(0)并从中获取值,在这种情况下将是名称="生命线"的保存节点。因此,如果您要执行saveItems.Item(1)并选择节点及其值,那么您将获得另一组节点。