如何按属性选择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中加载所需数据吗?
如果可以使用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)并选择节点及其值,那么您将获得另一组节点。