使用C#中的属性从XML读取时出现问题

时间:2011-04-09 15:59:21

标签: c# xml nodes

我正在创建一个从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);

问题是我希望能够通过“名称”属性选择节点,并且我不知道使用列表框来执行此操作。 那些“生命线”和“地狱代码”就像帐户名,用户应该选择要加载的帐号数据。

3 个答案:

答案 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)

  1. 确保您给予了正确的权利 xml文件名,
  2. 确保您的xml文件不为空
  3. 并尝试此XmlNode seconds = saveItems.Item(0).SelectSingleNode("Seconds").Value;
  4. 检查here
  5. 并检查here