У меня есть файл xml, и мне нужно сохранить значения в списке, чтобы использовать его позже. Файл xml содержит в основном ints and strings и выглядит так:
<AllThings>
<Anythings>
<Anything Step = "1" Name = "1">
<Somethings>
<Something Id = "10">
<Things>
<Thing Id = "11">abc</Thing>
<Thing Id = "12">123</Thing>
</Things>
</Something>
<Something Id = "20">
<Things>
<Thing Id = "21">cde</Thing>
<Thing Id = "22">345</Thing>
</Things>
</Something>
<Something Id = "30">
<Things>
<Thing Id = "31">efg</Thing>
<Thing Id = "32">567</Thing>
</Things>
</Something>
<Something Id = "40">
<Things>
<Thing Id = "41">ghi</Thing>
<Thing Id = "42">789</Thing>
</Things>
</Something>
</Somethings>
</Anything>
<Anything Step = "2" Name = "2">
<Somethings>
<Something Id = "10">
<Things>
<Thing Id = "11">aaa</Thing>
<Thing Id = "12">111</Thing>
</Things>
</Something>
<Something Id = "20">
<Things>
<Thing Id = "21">ccc</Thing>
<Thing Id = "22">333</Thing>
</Things>
</Something>
<Something Id = "30">
<Things>
<Thing Id = "31">eee</Thing>
<Thing Id = "32">555</Thing>
</Things>
</Something>
<Something Id = "40">
<Things>
<Thing Id = "41">ggg</Thing>
<Thing Id = "42">777</Thing>
</Things>
</Something>
</Somethings>
</Anything>
</Anythings>
</AllThings>
Каков наилучший способ получить значения из такого XML-файла и сохранить его в списках?
Я пытался с помощью using System.Xml; создать читалку и сделать reader.ReadToFollowing("Something") в сочетании с reader.GetAttribute("Id"), но этого недостаточно. В большинстве руководств xml выглядит так:
<Animal type = "cat">
<Name>Bob</Name>
<Age>8</Age>
</Animal>
И там это работает
Следующее может быть полезно: stackoverflow.com/a/73640395/10024425 и stackoverflow.com/a/68232320/10024425
Я думаю, вы пропустили повторение рекурсивно с помощью
.ChildNodes.OfType<XmlNode>().
Самый простой способ сделать это — использовать XmlSerialization. Для этого вам нужно будет создать структуру вложенного класса, соответствующую вашему xml. Существует множество утилит, которые сделают это автоматически (если вы ищете класс convert xml to c#), но я всегда чувствую, что полезно знать, как создать это самостоятельно.
Я всегда начинаю с внешней оболочки и продвигаюсь внутрь. Поэтому я сначала беру корневой элемент. AllThings имеет только один элемент AnyThings, поэтому этот класс легко создать (вам понадобится using System.Xml.Serialization;):
[XmlRoot]
public class AllThings
{
[XmlElement]
public Anythings Anythings { get; set; }
}
Далее мы смотрим на Anythings. Он содержит кучу элементов Anything, поэтому мы соответственно создаем следующий класс:
public class Anythings
{
[XmlElement]
public List<Anything> Anything { get; set; }
}
Здесь следует отметить только одну вещь: связка Anything представлена как List<Anything>.
Спускаемся снова вниз:
public class Anything
{
[XmlElement]
public Somethings Somethings { get; set; }
[XmlAttribute]
public int Step { get; set; }
[XmlAttribute]
public string Name { get; set; }
}
Здесь есть еще немного интересного: помимо XmlElement у нас есть два XmlAttributes. В вашем случае имя атрибута может легко быть int, учитывая значения в вашем xml, но, на мой взгляд, атрибут с именем Имя кричит, чтобы быть строкой!
И дальше вниз:
public class Somethings
{
[XmlElement]
public List<Something> Something { get; set; }
}
public class Something
{
[XmlElement]
public Things Things { get; set; }
[XmlAttribute]
public int Id { get; set; }
}
public class Things
{
[XmlElement]
public List<Thing> Thing { get; set; }
}
Все они строятся так же, как и раньше, оставляя только еще один класс:
public class Thing
{
[XmlAttribute]
public int Id { get; set; }
[XmlText]
public string Text { get; set; }
}
Это (наконец) добавляет что-то новое, базовый элемент XmlText, который представляет значение узла.
После настройки классов остается только вызвать встроенный десериализатор, например:
var xml = "<AllThings><Anythings><Anything Step=\"1\" Name=\"1\"><Somethings><Something Id=\"10\"><Things><Thing Id=\"11\">abc</Thing><Thing Id=\"12\">123</Thing></Things></Something><Something Id=\"20\"><Things><Thing Id=\"21\">cde</Thing><Thing Id=\"22\">345</Thing></Things></Something><Something Id=\"30\"><Things><Thing Id=\"31\">efg</Thing><Thing Id=\"32\">567</Thing></Things></Something><Something Id=\"40\"><Things><Thing Id=\"41\">ghi</Thing><Thing Id=\"42\">789</Thing></Things></Something></Somethings></Anything><Anything Step=\"2\" Name=\"2\"><Somethings><Something Id=\"10\"><Things><Thing Id=\"11\">aaa</Thing><Thing Id=\"12\">111</Thing></Things></Something><Something Id=\"20\"><Things><Thing Id=\"21\">ccc</Thing><Thing Id=\"22\">333</Thing></Things></Something><Something Id=\"30\"><Things><Thing Id=\"31\">eee</Thing><Thing Id=\"32\">555</Thing></Things></Something><Something Id=\"40\"><Things><Thing Id=\"41\">ggg</Thing><Thing Id=\"42\">777</Thing></Things></Something></Somethings></Anything></Anythings></AllThings>";
var serializer = new XmlSerializer(typeof(AllThings));
using (var reader = new StringReader(xml))
{
var allThings = (AllThings)serializer.Deserialize(reader);
//do something with allThings;
}
Если вы используете отладчик для проверки allThings, вы обнаружите, что это объект c# со структурой, точно соответствующей вашему xml. Это означает, что вы можете получить доступ к его значениям с таким синтаксисом, как:
var test = allThings.Anythings.Anything[0].Somethings.Something[0].Things.Thing[0].Text;
Следующий код протестирован и работает
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication51
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(AllThings));
AllThings allthings = (AllThings)serializer.Deserialize(reader);
}
}
public class AllThings
{
[XmlArray("Anythings")]
[XmlArrayItem("Anything")]
public List<AnyThing> anythings { get;set;}
}
public class AnyThing
{
[XmlAttribute()]
public int Step { get;set;}
[XmlAttribute()]
public int Name { get; set; }
[XmlArray("Somethings")]
[XmlArrayItem("Something")]
public List<Something> somethings { get; set; }
}
public class Something
{
[XmlAttribute()]
public int Id { get; set; }
[XmlArray("Things")]
[XmlArrayItem("Thing")]
public List<Thing> things { get;set;}
}
public class Thing
{
[XmlAttribute()]
public int Id { get; set; }
[XmlText]
public string value { get; set; }
}
}
В ваших списках есть два тега, такие как Somethings и SomeThing. Если в вашем xml нет двух тегов для массивов, используйте [XmlElement(tag)] вместо XmlArray и XmlArrayItem.
Какие поля вы получаете для типа, имени и возраста?