【问题标题】:Parsing XML data in C# and show into ListBox在 C# 中解析 XML 数据并显示到 ListBox
【发布时间】:2016-04-21 00:38:25
【问题描述】:

我正在尝试使用 Visual Studio 解析 C# 中的 XML 文件并在 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>

我用 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;
    }
}

【问题讨论】:

  • LikedPerson 可以出现多次吗?
  • 你还需要为此更新你的类,因为它现在只能在 CLR 对象中出现一次。

标签: c# xml visual-studio parsing xml-serialization


【解决方案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);

您还需要为 Persons 类添加不带参数的构造函数。

【讨论】:

  • 它在 XmlSerializer... 行上给了我以下错误:Proiect_SBC.Persons 由于其保护级别而无法访问。只能处理公共类型。
  • 公开类定义:public class Persons{...}
  • 现在我在 var person = (Persons) mySerializer.Deserialize(myFileStream); 上有一个错误。 ->> {"XML 文档中存在错误 (10, 2)。"}
  • 这是一个不错的建议@RadinGospodinov,但如果不对类(或 XML)进行重大改造,将无法工作......
【解决方案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- 为 XML 定义使用 XSD。例如:

    <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- Persons 类应如下所示:

    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 节点并获取它的名称/年龄。为了避免代码重复,您可以创建一个方法,该方法接受 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.        
          }        
      }
      

      【讨论】:

      • 我还添加了“private System.Xml.XmlNode likePerson;”在 Persons.cs 中,现在它在 PropertyGrid 中向我显示“LikedPerson”,但它旁边没有显示任何内容......(如姓名、年龄......)
      • 你能更新你的代码吗?我会尝试重现您的问题。
      • 我无法评论另一个答案:XML 文档中存在错误 (10, 2)。您的根元素不是“Persons”,这就是您收到此错误的原因。
      猜你喜欢
      • 1970-01-01
      • 2012-11-21
      • 2015-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多