在c#中读取带有属性的XML的问题
本文关键字:属性 XML 问题 读取 | 更新日期: 2023-09-27 17:49:48
我正在制作一个应用程序,它从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>
问题是,我想通过从列表框中加载"name"来指定"save"
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);
}
但是没有加载
===================================================================
只是为了让这个问题更容易理解。这里的代码工作,并加载应用程序所需的所有数据,但它只从"生命线"节点加载。在编译时,没有异常,一切都运行良好。
先。StreamReader sr = new System.IO.StreamReader(@" saved .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);
问题是,我想有一个能力来选择节点的"名称"属性,我不知道如何使用列表框。这些"生命线"answers"地狱代码"就像帐户名,用户应该选择加载哪些帐户数据。
您的XPath查询是关闭的-您目前使用的是name作为文字而不是它的值,并且您需要在它周围使用单引号-所以替换这个
XmlNodeList saveItems = save.SelectNodes("Storage/Save[@Name = name]");
:
XmlNodeList saveItems = save.SelectNodes(string.Format("storage/Save[@Name = '{0}']", name));
Edit:在Xpath查询中也需要小写的storage
- fixed
这个示例代码为我工作-这应该有助于你找到你的其他问题在哪里:
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到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);
回答你的另一个重复问题:
我已经尝试从列表框项目内容的字符串,然后使用这样的行
XmlNodeList saveItems = save.SelectNodes(string。Format("storage/Save[@Name = '{0}']", name));
变量"name"是来自列表框项的字符串。在编译时,此代码给出异常。有人知道如何按属性选择并从XML中加载所需数据吗?
我怀疑你没有得到正确的值从你的ListBox
。这完全取决于你如何填充它。如果您只是使用设计器用string
的名称填充ListBox
,那么您应该使用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而不是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);
- 确保你给予了权利
- 确保xml文件不是空的
- 并尝试此
XmlNode seconds = saveItems.Item(0).SelectSingleNode("Seconds").Value;
- 检查这里
- 和点击这里