从 C# 中具有属性的 XML 读取的问题 [英] Problem with reading from an XML with attributes in C#

查看:38
本文介绍了从 C# 中具有属性的 XML 读取的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个从 XML 文件保存和加载数据的应用程序.

I'm making an application which saves and loads data from an 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> 
</storage>

问题是我想通过以这种方式从列表框中加载名称"来指定保存"

The thing is that I whant to specify the "save" by loading "name" from a listbox in such a way

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

当我尝试运行应用程序时,编译器在

When I try to run the application the compiler gives NullReferenceException was unhandled "Object reference not set to an instance of an object" on

XmlNode seconds = saveItems.Item(0).SelectSingleNode("Seconds");

所以我的问题是出了什么问题,我该怎么办?

So my question is what's wrong and what should I do?

我什至试过这个

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

但根本没有加载

======================================================================

===================================================================

只是为了让这个问题更容易理解.这是运行并加载应用程序所需的所有数据的代码,但它仅从生命线"节点加载.编译时,无一例外,一切正常.

just to get this quetion easier to understand. Here is the code which works and loads all needed data for application, BUT it loads only from "Lifeline" node. While compiling, there are no exception and all works pretty fine.

System.IO.StreamReader sr = new System.IO.StreamReader(@"Saves.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);

问题是我希望能够通过名称"属性选择节点,而我不知道使用列表框来做这件事.那些Lifeline"和Hellcode"就像账户名,用户应该选择加载哪个账户数据.

The problem is that I want to have an ability to choose nodes by "Name" attribute, and I don't know hot to do it using the listbox. Those "Lifeline" and "Hellcode" are like account names, and the user should choose which account data to load.

推荐答案

要回答您对其他重复问题的跟进:

To answer your followup on your other duplicate question:

我尝试从列表框项目内容中获取字符串,然后使用这样的一行

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

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

变量name"是来自列表框项目的字符串.编译此代码时会出现异常.有人知道如何按属性选择并从该 XML 加载需要的数据吗?

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?

我怀疑您没有从 ListBox 中获取正确的值.这一切都取决于你如何填充它.如果您只是使用设计器用您的 string 名称填充您的 ListBox,则您应该使用 SelectedItem 属性以获取所选名称.另一方面,如果您填充了 ListBox 设置 DataSource,设置ValueMember 属性到适当的属性名称并使用 SelectedValue 获取值.

I suspect that you're not getting the right values off of your ListBox. It all depends on how you populated it. If you just used the designer to fill your ListBox with your string names, you should be using the SelectedItem property to get the selected name. If on the other hand you populated your ListBox setting the DataSource, set the ValueMember property to the appropriate property name and use SelectedValue to get the value.

尽管您从未提及异常是什么,这只是一个有根据的猜测.

Though since you never mentioned what the exception was, this is all just an educated guess.

您最初的问题是您使用了错误的 XPath.由于它是错误的,因此对第一个结果的所有后续访问都返回了 null,从而产生了 NullReferenceException.BrokenGlass 的回答涵盖了使用正确的 XPath.

Your problem initially was that you were using the wrong XPath. Since it was wrong, all following accesses to the first result returned null yielding a NullReferenceException. BrokenGlass' answer covers the using the correct XPath.

如果您向我们展示的 XML 确实是文件内容中的内容并且您获得了适当的 name 值,那么一切都应该在这里工作.

If the XML you are showing us is indeed what is in the contents of the file and you are getting an appropriate name value, then everything should work here.

总的来说,代码可以简化很多.我在这里使用了一些 LINQ 只是为了更容易处理无效名称.您应该会发现这是工作代码.

Overall, the code could be simplified much more. I use some LINQ here just to make dealing with invalid names easier. You should find that this is working code.

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.

I would prefer LINQ to XML here as it is much more cleaner. This should also work with the xmlStr provided above.

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

这篇关于从 C# 中具有属性的 XML 读取的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆