2016-01-15 3 views
4

Я пытаюсь проанализировать XML-файл на C# с помощью Visual Studio и показать данные в ListBox, но я не знаю, как его разобрать, когда я имею дело с вложенный XML-файл.Анализ данных XML на C# и отображение в ListBox

Это код из файла 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> 

Код я написал в C# успешно вернуть мне только имя, пол и возраст для каждого человека, но я не знаю, как написать, чтобы показать мне также 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; 
     } 
    } 

Это определение Persons.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; 
    } 
} 
+0

Может ли 'LikedPerson' встречаться более одного раза? –

+0

Да, это может ... – user3063909

+0

Вам нужно будет обновить свой класс для этого, а затем, поскольку он стоит сейчас, это может произойти только один раз в объекте CLR. –

ответ

2
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.

+0

Это дает мне следующую ошибку в строке XmlSerializer ...: Proiect_SBC.Persons недоступен из-за уровня защиты. Могут обрабатываться только общедоступные типы. – user3063909

+0

Сделать определение класса общедоступным: public class Persons {...} –

+0

Теперь у меня есть ошибка в var person = (Person) mySerializer.Deserialize (myFileStream); - >> {«В документе XML есть ошибка (10, 2)."} – user3063909

0

Вы можете получить узел LikedPerson и получить его имя/возраст, как сейчас. Во избежание дублирования кода вы можете создать метод, который принимает 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.   
    }   
} 
+0

Я также добавил« private System.Xml.XmlNode lovedPerson; »в Person.cs , и теперь он показывает мне «LikedPerson» в PropertyGrid, но он ничего не показывает рядом с ним ... (например, имя, возраст ...) – user3063909

+0

Можете ли вы обновить свой код, пожалуйста? Я попытаюсь воспроизвести ваша проблема. – denisv

+0

Я не могу прокомментировать другой ответ: в документе XML есть ошибка (10, 2). Корневой элемент не «Лица», поэтому вы получаете эту ошибку. – denisv

1

Самый естественный способ сделать это состоит в использовании 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 объекты.

1

@ 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- Лица класс должен выглядеть следующим образом:

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); 

В результате получится класс корня со списком лиц.

Cheers.

Смежные вопросы