我正在创建一个从XML文件中保存和加载数据的应用程序。
这是我的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>
</storage>
问题是我想通过以这种方式从列表框中加载“名称”来指定“保存”
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);
string name = lstSave.SelectedItem.ToString();
XmlNodeList saveItems = save.SelectNodes("Storage/Save[@Name = name]");
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);
当我尝试运行应用程序时,编译器给出NullReferenceException未处理“对象引用未设置为对象的实例”
XmlNode seconds = saveItems.Item(0).SelectSingleNode("Seconds");
所以我的问题是什么错,我该怎么办?
编辑: 我甚至试过这个
foreach (XmlNode xn in saveItems)
{
sec = Int32.Parse(xn["Seconds"].InnerText);
min = Int32.Parse(xn["Minutes"].InnerText);
hour = Int32.Parse(xn["Hours"].InnerText);
day = Int32.Parse(xn["Days"].InnerText);
month = Int32.Parse(xn["Months"].InnerText);
year = Int32.Parse(xn["Years"].InnerText);
health = Int32.Parse(xn["Health"].InnerText);
mood = Int32.Parse(xn["Mood"].InnerText);
}
但没有任何东西加载
=============================================== ====================
只是为了让这个问题更容易理解。 这是代码,它可以为应用程序工作和加载所有需要的数据,但它只从“生命线”节点加载。在编译时,没有例外,所有工作都很好。
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);
问题是我希望能够通过“名称”属性选择节点,并且我不知道使用列表框来执行此操作。 那些“生命线”和“地狱代码”就像帐户名,用户应该选择要加载的帐号数据。
答案 0 :(得分:4)
您的XPath查询已关闭 - 您当前正在使用名称作为文字,而不是其值,您还需要单引号 - 所以请替换此
XmlNodeList saveItems = save.SelectNodes("Storage/Save[@Name = name]");
使用:
XmlNodeList saveItems = save.SelectNodes(string.Format("storage/Save[@Name = '{0}']", name));
编辑:在Xpath查询中也需要小写storage
- 已修复
此示例代码适用于我 - 这可以帮助您找到其他问题所在:
System.IO.StreamReader sr = new System.IO.StreamReader(@"test.xml");
System.Xml.XmlTextReader xr = new System.Xml.XmlTextReader(sr);
System.Xml.XmlDocument save = new System.Xml.XmlDocument();
save.Load(xr);
string name = "Hellcode";
XmlNodeList saveItems = save.SelectNodes(string.Format("storage/Save[@Name = '{0}']", name));
XmlNode seconds = saveItems.Item(0).SelectSingleNode("Seconds");
int sec = Int32.Parse(seconds.InnerText);
另外,我建议您将SelectNodes()
替换为SelectSingleNode()
:
XmlNode saveItem = save.SelectSingleNode(string.Format("storage/Save[@Name = '{0}']", name));
XmlNode seconds = saveItem.SelectSingleNode("Seconds");
修改:
正如所建议的,XML解析的另一种选择是Linq to XML - 这几乎是现在的标准,如果你不需要,不要使用其他任何东西。这使得这个样本更短:
XDocument doc = XDocument.Load("test.xml");
var saveItem = doc.Descendants("Save")
.Where(x => (string)x.Attribute("Name") == name)
.Single();
int sec = Convert.ToInt32(saveItem.Element("Seconds").Value);
答案 1 :(得分:1)
要回答您对其他重复问题的跟进:
我尝试从列表框项目内容中获取字符串,然后使用这样的行
XmlNodeList saveItems = save.SelectNodes(string.Format(“storage / Save [@Name ='{0}']”,name));
变量“name”是listboxe项目中的字符串。编译时,此代码提供异常。有人知道如何通过属性选择并加载来自该XML的nedeed数据吗?
我怀疑你没有从ListBox
获得正确的价值。这一切都取决于你如何填充它。如果您刚刚使用设计人员用ListBox
名称填充string
,则应使用SelectedItem
属性获取所选名称。另一方面,如果您填充了ListBox设置DataSource
,请将ValueMember
属性设置为相应的属性名称,并使用SelectedValue
获取值。
虽然你从未提及异常是什么,但这只是一个有根据的猜测。
您最初的问题是您使用的是错误的XPath。由于它是错误的,因此对第一个结果的所有后续访问都返回null
,产生NullReferenceException
。 BrokenGlass的答案涵盖了使用正确的XPath。
如果您向我们展示的XML确实是文件和的内容,那么您将获得适当的name
值,那么一切都应该在这里工作。
总的来说,代码可以简化得更多。我在这里使用一些LINQ只是为了更容易处理无效名称。您应该会发现这是有效的代码。
var xmlStr = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
<storage>
<Save Name =""Lifeline"">
<!-- etc... (trimmed off for brevity) -->
</Save>
<Save Name =""Hellcode"">
<!-- etc... -->
</Save>
</storage>
";
var doc = new XmlDocument();
doc.LoadXml(xmlStr);
var name = "Hellcode";
var settings =
doc.SelectNodes(String.Format("/storage/Save[@Name='{0}']", name))
.Cast<XmlElement>()
.Select(e => new
{
Seconds = Convert.ToInt32(e["Seconds"].InnerText),
Minutes = Convert.ToInt32(e["Minutes"].InnerText),
Hours = Convert.ToInt32(e["Hours"].InnerText),
Days = Convert.ToInt32(e["Days"].InnerText),
Months = Convert.ToInt32(e["Months"].InnerText),
Years = Convert.ToInt32(e["Years"].InnerText),
Health = Convert.ToInt32(e["Health"].InnerText),
Mood = Convert.ToInt32(e["Mood"].InnerText),
})
.SingleOrDefault();
Trace.WriteLine("settings: " + settings);
我更喜欢LINQ to XML,因为它更清洁。这也适用于上面提供的xmlStr
。
var doc = XDocument.Parse(xmlStr);
var name = "Hellcode";
var settings =
doc.Element("storage")
.Elements("Save")
.Where(e => e.Attribute("Name").Value == name)
// or if using XPath, the above could be replaced with:
// doc.XPathSelectElements(String.Format("/storage/Save[@Name='{0}']", name))
.Select(e => new
{
Seconds = (int)e.Element("Seconds"),
Minutes = (int)e.Element("Minutes"),
Hours = (int)e.Element("Hours"),
Days = (int)e.Element("Days"),
Months = (int)e.Element("Months"),
Years = (int)e.Element("Years"),
Health = (int)e.Element("Health"),
Mood = (int)e.Element("Mood"),
})
.SingleOrDefault();
Trace.WriteLine("settings: " + settings);
答案 2 :(得分:0)