在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"地狱代码"就像帐户名,用户应该选择加载哪些帐户数据。

在c#中读取带有属性的XML的问题

您的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);
  1. 确保你给予了权利
  2. 确保xml文件不是空的
  3. 并尝试此XmlNode seconds = saveItems.Item(0).SelectSingleNode("Seconds").Value;
  4. 检查这里
  5. 和点击这里