简体   繁体   English

如何通过属性选择XML节点并使用其子节点数据?

[英]How to select XML node by attribute and use it's child nodes data?

Here is my XML file 这是我的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> 

Here is a code which get's data from XML and loads it into application. 这是一个从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);

The problem is that this code loads data inly from "Lifeline" node. 问题在于此代码从“生命线”节点中间接加载数据。 I would like to use a listbox and be able to choose from which node to load data. 我想使用一个列表框,并能够选择从哪个节点加载数据。

I've tried to take string from listbox item content and then use such a line 我试图从列表框项目内容中获取字符串,然后使用这样的行

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

variable "name" is a string from listboxe's item. 变量“名称”是列表框项目中的字符串。 While compiled this code gives exception. 在编译时,此代码给出了异常。 Do somebody knows a way how to select by attribute and load nedeed data from that XML? 有人知道一种如何通过属性选择并从该XML加载所需数据的方法吗?

If you can use XElement: 如果可以使用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
}

Personally I like classes that have properties that convert to and from the XElement to hide that detail from the main program. 就个人而言,我喜欢类具有在XElement之间转换的属性,以在主程序中隐藏该细节。 IE say the Save class takes an XElement node in the constructor, saves it internally globally, and the properties read/write to it. IE表示Save类在构造函数中使用一个XElement节点,将其全局内部保存,并且对其进行读取/写入。

Example class: 示例类:

  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));
      }
    }
   }

Then you can change the search to something like: 然后,您可以将搜索更改为以下内容:

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

The select nodes is returning two XmlNode objects. 选择节点将返回两个XmlNode对象。

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

Later in your code you seem to be selecting the first one and with saveItems.Item(0) and getting values from it which in this case would be the save node with the Name="LifeLine". 在代码的后面,您似乎选择了第一个,并带有saveItems.Item(0)并从中获取值,在这种情况下,这将是具有Name =“ LifeLine”的保存节点。 So if you were to do saveItems.Item(1) and select nodes and its values then you would get the other set of nodes. 因此,如果要执行saveItems.Item(1)并选择节点及其值,则将获得另一组节点。

Since it is not that much data, I'd suggest loading all information to a list of saves(constructor) and then drawing from there which one the user would like to use... 由于数据量不大,我建议将所有信息加载到saves(构造函数)列表中,然后从那里绘制用户想要使用的信息...

As for things not working, I personally use a lower level approach to get my data and it is not error prone. 对于不起作用的情况,我个人使用较低级别的方法来获取我的数据,并且它不容易出错。 Remodeling it to fit your problem a bit: 重塑它以适合您的问题:

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 = "";
}

Basically throw everything in the xml file into a list of objects and manipulate that list to fill the listbox. 基本上将xml文件中的所有内容都放入对象列表中,并操纵该列表以填充列表框。 Instead of having Saves name = "...", have a name attribute as the first attribute in the save. 而不是让Saves name =“ ...”,而是将name属性作为保存中的第一个属性。

Code tags hate me. 代码标签讨厌我。 Why they break so easily ( ._.) 为什么它们这么容易破裂(._。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM