Анализ XML-данных на С# и отображение в ListBox
Я пытаюсь проанализировать XML файл на С# с помощью Visual Studio и показать данные в ListBox, но я не знаю, как его разобрать, когда я имею дело с вложенным XML файлом.
Это код из файла XML:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE root [
<!ELEMENT root (Persons*)>
<!ELEMENT Persons (name)>
<!ELEMENT IsMale (#PCDATA)>
<!ELEMENT Age (#PCDATA)>
<!ELEMENT Name (#PCDATA)>
<!ELEMENT LikedPerson (name)>
]>
<root>
<Persons name ="Bob">
<IsMale>true</IsMale>
<Age>30</Age>
<LikedPerson name ="Iulia">
<IsMale>false</IsMale>
<Age>32</Age>
</LikedPerson>
</Persons>
</root>
Код, который я написал на С#, успешно возвращает мне только имя, пол и возраст для каждого человека, но я не знаю, как писать, чтобы показать мне также person_liked:
private void LoadPersons()
{
XmlDocument doc = new XmlDocument();
doc.Load("Baza_de_cunostinte.xml");
foreach (XmlNode node in doc.DocumentElement)
{
string name = node.Attributes[0].Value;
int age = int.Parse(node["Age"].InnerText);
bool isMale = bool.Parse(node["IsMale"].InnerText);
// Persons likedPerson.name = Persons.node.Attributes[0].Value ?
// .....
listBox.Items.Add(new Persons(name, age, isMale, likedPerson));
}
}
private void listBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBox.SelectedIndex != -1)
{
propertyGrid1.SelectedObject = listBox.SelectedItem;
}
}
Это определение Person.cs:
class Persons
{
public string Name { get; private set; }
public int Age { get; private set; }
public bool IsMale { get; private set; }
public Persons LikedPerson { get; private set; }
public Persons(string name, int age, bool isMale, Persons likedPerson)
{
Name = name;
Age = age;
IsMale = isMale;
LikedPerson = likedPerson;
}
}
Ответы
Ответ 1
XmlSerializer mySerializer = new XmlSerializer(typeof(Persons));
// Create a FileStream or textreader to read the xml data.
FileStream myFileStream = new FileStream("xmldatafile.xml", FileMode.Open);
var person = (Persons) mySerializer.Deserialize(myFileStream);
Вам также нужно добавить конструктор без параметра для класса Person.
Ответ 2
Самый естественный способ сделать это - использовать XmlSerializer
, как было предложено, но для этого вам придется немного реорганизовать свои классы:
[XmlType(Namespace="", TypeName="root")]
public class PersonCollection
{
[XmlElement(Namespace="", ElementName="Persons")]
public List<Persons> People { get; set; }
}
public class Persons
{
[XmlAttribute(AttributeName="name")]
public string Name { get; set; }
public int Age { get; set; }
public bool IsMale { get; set; }
public Persons LikedPerson { get; set; }
public Persons() { }
public Persons(string name, int age, bool isMale, Persons likedPerson)
{
Name = name;
Age = age;
IsMale = isMale;
LikedPerson = likedPerson;
}
}
Затем вы можете сделать что-то вроде этого:
XmlSerializer ser = new XmlSerializer(typeof(PersonCollection));
PersonCollection pc = (PersonCollection)ser.Deserialize(File.OpenRead("Baza_de_cunostinte.xml"));
foreach (Persons p in pc.People)
{
// you now have a fully populated object
}
а список pc.People
будет содержать ваши объекты Persons
.
Ответ 3
@user3063909,
1- Используйте XSD для определения XML. Пример:
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="Persons" maxOccurs="unbounded" minOccurs="0" type="Persons"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="Persons">
<xs:sequence>
<xs:element type="xs:string" name="IsMale"/>
<xs:element type="xs:int" name="Age"/>
<xs:element name="LikedPerson" type="Persons"/>
</xs:sequence>
<xs:attribute type="xs:string" name="name" />
</xs:complexType>
</xs:schema>
2- Класс Person должен выглядеть следующим образом:
namespace StackOverflow
{
public class Root
{
[XmlElement("Persons")]
public List<Persons> Persons { get; set; }
}
public class Persons
{
public string IsMale { get; set; }
public int Age { get; set; }
public Persons LikedPerson { get; set; }
[XmlAttribute("Name")]
public string Name { get; set; }
}
}
3- Класс сериализатора:
namespace StackOverflow
{
public class XmlSerializerHelper<T> where T : class
{
private readonly XmlSerializer _serializer;
public XmlSerializerHelper()
{
_serializer = new XmlSerializer(typeof(T));
}
public T BytesToObject(byte[] bytes)
{
using (var memoryStream = new MemoryStream(bytes))
{
using (var reader = new XmlTextReader(memoryStream))
{
return (T)_serializer.Deserialize(reader);
}
}
}
}
}
4- И, наконец, назовите его так:
var fileBytes = File.ReadAllBytes("C:/xml.xml");
var persons = new XmlSerializerHelper<Root>().BytesToObject(fileBytes);
Результатом будет корневой класс со списком лиц.
Приветствия.
Ответ 4
Вы можете получить LikedPerson node и получить его имя/возраст, как сейчас. Во избежание дублирования кода вы можете создать метод, который принимает XmlNode, рекурсивно решает его и возвращает Person. Но лучший способ - использовать XmlSerializer
foreach (XmlNode node in doc.DocumentElement)
{
string name = node.Attributes[0].Value;
int age = int.Parse(node["Age"].InnerText);
bool isMale = bool.Parse(node["IsMale"].InnerText);
var likedPerson = node.SelectSingleNode("LikedPerson");
if (likedPerson != null){
string name = likedPerson.Attributes[0].Value;
//age, gender, etc.
}
}