Проблема с чтением из XML с атрибутами в C # - PullRequest
0 голосов
/ 09 апреля 2011

Я делаю приложение, которое сохраняет и загружает данные из файла 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 ]

4 голосов
/ 09 апреля 2011

Ваш запрос XPath отключен - в настоящее время вы используете имя в качестве литерала, а не его значение, также вам необходимо заключить его в одинарные кавычки - поэтому замените этот

XmlNodeList saveItems = save.SelectNodes("Storage/Save[@Name = name]");

на:

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

Редактировать: также требуется строчная буква storage в запросе Xpath - исправлено

Этот пример кода работает для меня - это должно помочь вам найти другие проблемы:

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 голос
/ 10 апреля 2011

Чтобы ответить на ваш ответ на другой дубликат вопроса:

Я пытался извлечь строку из содержимого элемента списка, а затем использовать такую ​​строку

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

переменная "name" является строкой из элемента listboxe. Во время компиляции этот код дает исключение. Кто-нибудь знает, как выбрать по атрибуту и ​​загрузить необходимые данные из этого XML?

Я подозреваю, что вы не получаете правильные значения от вашего 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);
0 голосов
/ 09 апреля 2011
  1. убедитесь, что вы даете право имя файла XML,
  2. убедитесь, что ваш XML-файл не пустой
  3. и попробуйте это XmlNode seconds = saveItems.Item(0).SelectSingleNode("Seconds").Value;
  4. отметьте здесь
  5. и отметьте здесь
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...