В C# System.Xml.Serialization есть сериализованные XML-данные.
Есть корневой класс, описывающий корневой элемент. Он содержит поля типа List, описанные в классах-потомках (например, Movie).
Я могу десериализовать свой XML-документ в класс и добавить новый элемент в список, просто используя List.Add или List.Insert:
cfg.Movies.Insert(0, new Movie("Newly added: Pulp Fiction", "1994"));
Но обратная операция не работает:
cfg.Movies.Remove(new Movie("To be removed: The Godfather", "1974"));
Итак, вопрос в том, как удалить элемент из списка классов xml?
Пример здесь: https://dotnetfiddle.net/WqCNoD
using System;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using System.Collections.Generic;
using System.Xml.Serialization;
public class Program
{
public static void Main()
{
string xmlString =
@"<favorites>
<movies>
<movie title = ""To be removed: The Godfather"" year = ""1974"" />
<movie title = ""The Terminator"" year = ""1984"" />
<movie title = ""Dark Knight"" year = ""2008"" />
</movies>
<books>
<book title = ""1984"" author = ""George Orwell"" />
<book title = ""Robinson Crusoe"" author = ""Daniel Defoe "" />
<book title = ""Frankenstein"" author = ""Mary Shelly"" />
</books>
<music>
<artist title = ""Beatles"" genre = ""rock"" />
<artist title = ""Queen"" genre = ""rock"" />
<artist title = ""Metallica"" rock = ""heavy metal"" />
</music>
</favorites>";
XDocument xdoc = XDocument.Parse(xmlString);
var xdocData = xdoc.ToString();
//DeSerialization
XmlSerializer serializer = new XmlSerializer(typeof(Favorites));
using (StringReader reader = new StringReader(xdoc.ToString()))
{
Favorites cfg = (Favorites) serializer.Deserialize(reader);
// Add & remove element
cfg.Movies.Insert(0, new Movie("Newly added: Pulp Fiction", "1994"));
cfg.Movies.Remove(new Movie("To be removed: The Godfather", "1974"));
//Serialization
XmlSerializer serializer2 = new XmlSerializer(cfg.GetType());
using (StringWriter writer = new StringWriter())
{
serializer2.Serialize(writer, cfg);
Console.WriteLine(writer.ToString());
}
}
}
[XmlRoot(ElementName = "favorites", DataType = "string", IsNullable = true)]
public class Favorites
{
//public string Name { get; set; }
[XmlArray("movies")]
[XmlArrayItem("movie")]
public List<Movie> Movies { get; set; }
public Favorites()
{
Movies = new List<Movie>();
}
}
public class Movie
{
[XmlAttribute("title")]
public string Title { get; set; }
[XmlAttribute("year")]
public string Year { get; set; }
public Movie() { }
public Movie(string title, string year)
{
Title = title;
Year = year;
}
}
}
Это не «xml-класс». Это обычный класс, у которого есть атрибуты сериализации.
Чем отличается этот запрос от вчерашнего? : stackoverflow.com/questions/49867071/…
@jdweng, это совершенно разные вопросы, у них только схожие xml данные. Первый касается вообще фильтрации xml-узлов, а этот относится конкретно к работе с XmlArray и List. Спасибо.





Когда вы создаете новый объект, его ссылки еще нет в списке. Вам нужно найти в списке элемент, который вы хотите удалить, а затем удалить его, используя результат поиска.
Что-то вроде:
var movieToRemove = cfg.Movies.SingleOrDefault(m => m.Title == "To be removed: The Godfather" && m.Year == "1974");
if (moveiToRemove != null)
cfg.Movies.Remove(movieToRemove);
Не могли бы вы объяснить, что здесь происходит - cfg.Movies.SingleOrDefault (m => m.Title == "Будет удалено: Крестный отец" && m.Year == "1974")? Можно ли это по-другому описать?
Это запрос Linq, который выбирает ровно один элемент в списке. Если элемента нет или есть несколько элементов, соответствующих критериям, возвращается значение по умолчанию (часто null). Критерий состоит в том, что Title и Year должны совпадать для каждого объекта m.
Я получаю исключение, если в списке нет подходящего элемента .. Есть ли способ справиться с этим без try-catch?
У вас не должно быть никаких исключений. У вас должен получиться null.
Вы пытаетесь удалить новый фильм, а не тот, который десериализовали.
Вы должны сначала найти фильм в своем списке, а затем удалить его.
Заменять
cfg.Movies.Remove(new Movie("To be removed: The Godfather", "1974"));
С участием
cfg.Movies.Remove(cfg.Movies.Find(x => x.Title == "Newly added: Pulp Fiction"));
Здесь не хватает знаний :( cfg.Movies.Find (x => x.Title == "Newly added: Pulp Fiction") - как это работает? Есть ли способ написать то же самое без "=>"?
"x => x.Title = = " Newly added: Pulp Fiction "- это инструкция предиката, в основном она гласит: найдите мне вхождение" x "в моем списке фильмов, где x.Title равно" Newly added: Pulp Fiction " ". Это реализовано в LINQ feautre C#. Вот руководство, чтобы вы могли понять его основы tutorialspoint.com/linq/linq_overview.htm Также почему вы не хотите использовать этот синтаксис?
Спасибо. Я предпочитаю использовать то, что хорошо понимаю, и LINQ пока для меня не совсем понятная тема. Поэтому я просто хотел знать - это как синтаксический сахар, или в данном случае у него нет альтернативы?
Вы можете начать с перехода к списку фильмов, и если один из них имеет в качестве названия искомое значение, сохраните его в переменной. После этого удалите из списка переменную, содержащую вхождение
Когда вы создаете новый объект, его ссылки еще нет в списке. Вам нужно найти в списке элемент, который вы хотите удалить, а затем удалить его, используя результат поиска. Что-то вроде:
var toRemove = cfg.Movies.Single(m => m.Title == "To be removed: The Godfather" && m.Year == "1974"); cfg.Movies.Remove(toRemove);