Добавлять к атрибуту в xml, новые элементы
Расскажите недалекому, пожалуйста, как добавлять новые элементы в xml файл, к определенному атрибуту. У нас идет форма. В ней мы вписываем Логин, пароль и и выбираем из списка пользователей, к кому мы прикрепим этот логин и пароль.
Это я к чему. Это логин и пароль от 1С. В комбобоксе находятся пользователи программы. У одного пользователя, может быть много аккаунтов 1с. И когда юзер заходит в программу, ему в форме выведутся только его пользователи.
Вот так выглядит структура xml файла
<Users1CList>
<User1C Mother="Юзер программы 1">
<USER1C>Логин1С</USER1C>
<UserPass>Пароль1С</UserPass>
</User1C>
<User1C Mother="Юзер программы 2">
<USER1C>Логин1С</USER1C>
<UserPass>Пароль1С</UserPass>
</User1C>
<User1C Mother="Юзер программы 3">
<USER1C>Логин1С</USER1C>
<UserPass>Пароль1С</UserPass>
</User1C>
И вот я хочу к Юзеру программы 1, добавить еще один профиль 1С. Не просто, чтобы вниз списка добавлялись новые значения, а мы потом бегали по всему файлу собирали совпадения, а именно к конкретному атрибуту. И выглядело это вот так
<Users1CList>
<User1C Mother="Юзер программы 1">
<USER1C>Логин1С</USER1C>
<UserPass>Пароль1С</UserPass>
<USER1C>Логин1С</USER1C>
<UserPass>Пароль1С</UserPass>
</User1C>
<User1C Mother="Юзер программы 2">
<USER1C>Логин1С</USER1C>
<UserPass>Пароль1С</UserPass>
</User1C>
<User1C Mother="Юзер программы 3">
<USER1C>Логин1С</USER1C>
<UserPass>Пароль1С</UserPass>
</User1C>
Форма добавления, выглядит вот так

Мы заполняем поля, добавляем в список и сохраняем его. Я использую сериализацию.
Вот так, выглядит кнопка сохранения
Users1C users1C = new Users1C();
foreach (ListViewItem item in lvUsers.Items)
{
if (item.Tag != null)
{
users1C.Users1CList.Add((User1C)item.Tag);
}
}
SerializeXML(users1C);
Кнопка добавления в список тоже примитивная
User1C user1C = new User1C(tbUsername.Text, tbNukeCode.Text, ((User)cbUserLogin.SelectedItem).Username);
Add(user1C);
Метод Add
ListViewItem list = new ListViewItem(user1C.UserName);
list.Tag = user1C;
lvUsers.Items.Add(list);
Жду критики, спасибо.
User1C
[Serializable]
public class Users1C
{
public Users1C() { }
public List<User1C> Users1CList = new List<User1C>() { };
}
[Serializable]
public class User1C
{
[XmlElement("USER1C")]
public string UserName { get; set; }
public string UserPass { get; set; }
[XmlAttribute("Mother")]
public string UserLogin { get; set; }
public User1C() { }
public User1C(string Username, string Userpass, string UserLogin)
{
this.UserName = Username;
this.UserPass = Userpass;
this.UserLogin = UserLogin;
}
}
Сохранение
XmlSerializer xml = new XmlSerializer(typeof(Users1C));
using (FileStream fs = new FileStream(pathUser1CFile, FileMode.OpenOrCreate))
{
xml.Serialize(fs, users1C);
}
Ответы (1 шт):
Жду критики, спасибо.
На протяжении многих лет я встречаю вопросы по XML, в которых путают элементы и атрибуты.
Элемент записывается в угловых скобках: <name>...</name>.
Атрибут состоит из пары ключ и значение: key="value".
Внутри элемента может быть множество других элементов и атрибутов.
Не путайте базовые понятия, используйте корректные термины XML!
XmlSerializer никак не использует атрибут [Serializable], поэтому его можно удалить. Чтобы не было путаницы, отмечу: атрибуты языка C# и атрибуты XML - разные вещи.
Параметр FileMode.OpenOrCreate при записи замените на FileMode.Create. В противном случае в файле может получиться некорректный результат, если будет записано меньше информации, чем было раньше.
У вас стоит задача в первую очередь найти определённого пользователя.
После того как данные загружены из xml-файла (десериализованы), это можно сделать так:
var user = users1C.Users1CList.First(u => u.UserLogin == "login1");
Далее нужно добавить новые данные этому пользователю. Это невозможно в рамках вашей модели: юзер имеет лишь одиночные свойства UserName и UserPass, а нужны коллекции.
Поэтому перепишем код.
Класс Users1C не имеет смысла, т. к. он содержит только одно свойство-список. Его следует удалить и использовать просто список List<User1C>
public class User1C
{
[XmlAttribute("Name")]
public string Name { get; set; }
[XmlElement]
public List<UserInfo> Info { get; set; }
public User1C() { }
public User1C(string name, string pass, string login)
{
Name = name;
Info = new List<UserInfo>();
Info.Add(new UserInfo { Pass = pass, Login = login });
}
}
public class UserInfo
{
public string Login { get; set; }
public string Pass { get; set; }
}
Это модели классов, которые будем использовать. Обратите внимание на имена свойств: Name, Login, Pass - без приставки User, потому что и так понятно, что они относятся к пользователю. Лишний словесный шум не нужен.
При желании, добавьте конструкторы классу UserInfo.
Коллекция пользователей - просто список:
private List<User1C> _users;
Сериализатор создаём следующим образом:
XmlSerializer _serializer = new XmlSerializer(
typeof(List<User1C>)
/*, new XmlRootAttribute("UserC1List")*/
);
И не нужно его создавать локально внутри метода, лучше сделать его полем класса (формы), чтобы был всего один экземпляр.
Уберите комментарий, чтобы задать желаемое имя корневому элементу.
Добавление пользователей в коллекцию:
_users.Add(new User1C("name1", "pass1", "login1"));
_users.Add(new User1C("name2", "pass2", "login2"));
Десериализация:
using (FileStream fs = new FileStream(filename, FileMode.Open))
{
_users = (List<User1C>)_serializer.Deserialize(fs);
}
Поиск пользователя по имени:
var user = _users.First(u => u.Name == "name1");
user.Info.Add(new UserInfo { Pass = "pass3", Login = "login3" });
И добавляем ему новую информацию.
Сериализация:
using (FileStream fs = new FileStream(filename, FileMode.Create))
{
_serializer.Serialize(fs, _users);
}
XML будет выглядеть следующим образом:
<?xml version="1.0"?>
<UserC1List xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<User1C Name="name1">
<Info>
<Login>login1</Login>
<Pass>pass1</Pass>
</Info>
<Info>
<Login>login3</Login>
<Pass>pass3</Pass>
</Info>
</User1C>
<User1C Name="name2">
<Info>
<Login>login2</Login>
<Pass>pass2</Pass>
</Info>
</User1C>
</UserC1List>