简体   繁体   English

使用不同类型的行反序列化 XML C#

[英]Deserialize XML with different type rows C#

Have a problem with deserialization XML.反序列化 XML 有问题。 Can not understand how make property data different based on xml attribute id xds generate one common property data that combine properties from data UserInfo + data UserTransactions无法理解如何根据data属性id xds 使属性data有所不同

Tried solution from this thread but have no luck Xml Example:尝试了这个线程的解决方案,但没有运气 Xml 示例:

<?xml version="1.0" encoding="UTF-8"?>
<document>
  <data id="UserInfo">
    <rows>
      <row id="123" Name="Alex" phone="+1234567890"></row>
      <row id="321" Name="Sally" phone="+1234567890"></row>
    <rows>
  </data>
  <data id="UserTransactions">
    <rows>
      <row UserId="123" amount="100.1" date="2022-07-03"></row>
      <row UserId="123" amount="-100.1" date="2022-07-03"></row>
      <row UserId="321" amount="1" date="2022-07-03"></row>
    <rows>
  </data>
</document>

Question: Is it possible to deserialize to some class what will have properties based on xml attributes?问题:是否可以反序列化为某些 class 将具有基于 xml 属性的属性? For example some like:例如一些喜欢:

    public class document
    {
        // based on <data id='UserInfo'>
        public UserInfoRow[] dataUserInfos { get; set; }
        // based on <data id='UserTransaction'>
        public UserTransactionRow[] dataUserTransactions { get; set; }
    }

Code that i'm tried我尝试过的代码

namespace test
{
    public class document
    {
        [XmlElement("data")]
        public documentData[] data { get; set; }
    }
    public class documentData
    {
        [XmlAttribute("id")]
        public string id { get; set; }

        [XmlArray("rows")]
        [XmlArrayItem("row")]
        public row[] rows { get; set; }
    }

    [XmlInclude(typeof(UserInfoRow)), XmlInclude(typeof(UserTransactionRow))]
    public class row { }
    public class UserInfoRow : row
    {
        [XmlAttribute("id")]
        public string id { get; set; }
        [XmlAttribute("Name")]
        public string Name { get; set; }
        [XmlAttribute("phone")]
        public string phone { get; set; }
    }
    public class UserTransactionRow : row
    {
        [XmlAttribute("UserId")]
        public string UserId { get; set; }
        [XmlAttribute("amount")]
        public string amount { get; set; }
        [XmlAttribute("date")]
        public string date { get; set; }
    }
}

No info from end classes没有来自最终课程的信息

手表

You cannot use an inherited class with your xml.您不能将继承的 class 与 xml 一起使用。 Inherited classes requires a type attribute in the xml.继承的类需要 xml 中的类型属性。 Instead you can use a custom IXmlSerialize like code below相反,您可以使用自定义 IXmlSerialize,如下面的代码

using System;
using System.Linq;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.Schema;

namespace ConsoleApp2
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.IgnoreWhitespace = true;
            XmlReader reader = XmlReader.Create(FILENAME);
            XmlSerializer serializer = new XmlSerializer(typeof(test.document));
            test.document doc = (test.document)serializer.Deserialize(reader);
 

        }

    }
 
}
namespace test
{
    public class document
    {        
        [XmlElement("data")]
        public documentData[] data { get; set; }
    }
    public class documentData : IXmlSerializable
    {
        [XmlAttribute("id")]
        public string id { get; set; }

        public List<UserInfoRow> userInfoRows { get; set; }
        public List<UserTransactionRow> userTransactionRows { get; set; }

        public void WriteXml(XmlWriter writer)
        {
 
        }

        public void ReadXml(XmlReader reader)
        {
            id = reader.GetAttribute("id");       
            XmlSerializer serializer = null;
            XmlReader xmlChildReader = null; 
            switch (id)
            {
                case "UserInfo":
                    serializer = new XmlSerializer(typeof(UserInfoRow)) ;
                    xmlChildReader = reader.ReadSubtree();
                    while (xmlChildReader.ReadToFollowing("row"))
                    {     
                        UserInfoRow userRow = (UserInfoRow)serializer.Deserialize(xmlChildReader);
                        if (userInfoRows == null) userInfoRows = new List<UserInfoRow>();
                        userInfoRows.Add(userRow);
                    }
                    break;
                case "UserTransactions":
                    serializer = new XmlSerializer(typeof(UserTransactionRow));
                    xmlChildReader = reader.ReadSubtree();
                    while (xmlChildReader.ReadToFollowing("row"))
                    {
                        UserTransactionRow userRow = (UserTransactionRow)serializer.Deserialize(xmlChildReader);
                        if (userTransactionRows == null) userTransactionRows = new List<UserTransactionRow>();
                        userTransactionRows.Add(userRow);
                    }
                    break;
            }
            reader.ReadEndElement();

        }

        public XmlSchema GetSchema()
        {
            return (null);
        }

    }
    [XmlRoot("row")]
    public class UserInfoRow
    {
        [XmlAttribute("id")]
        public string id { get; set; }
        [XmlAttribute("Name")]
        public string Name { get; set; }
        [XmlAttribute("phone")]
        public string phone { get; set; }
    }
    [XmlRoot("row")]
    public class UserTransactionRow
    {
        [XmlAttribute("UserId")]
        public string UserId { get; set; }
        [XmlAttribute("amount")]
        public string amount { get; set; }
        [XmlAttribute("date")]
        public string date { get; set; }
    }
}

Here is another solution that is more compact.这是另一个更紧凑的解决方案。 I eliminated the documentData class我消除了documentData class

using System;
using System.Linq;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.Schema;

namespace ConsoleApp2
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.IgnoreWhitespace = true;
            XmlReader reader = XmlReader.Create(FILENAME);
            XmlSerializer serializer = new XmlSerializer(typeof(test.document));
            test.document doc = (test.document)serializer.Deserialize(reader);
 

        }

    }
 
}
namespace test
{
    public class document : IXmlSerializable
    {        
 
        public string id { get; set; }

        public List<UserInfoRow> userInfoRows { get; set; }
        public List<UserTransactionRow> userTransactionRows { get; set; }

        public void WriteXml(XmlWriter writer)
        {
 
        }

        public void ReadXml(XmlReader reader)
        {
            XmlSerializer serializer = null;
            XmlReader xmlChildReader = null;

            while (reader.ReadToFollowing("data"))
            {

                id = reader.GetAttribute("id");
                switch (id)
                {
                    case "UserInfo":
                        serializer = new XmlSerializer(typeof(UserInfoRow));
                        xmlChildReader = reader.ReadSubtree();
                        while (xmlChildReader.ReadToFollowing("row"))
                        {
                            UserInfoRow userRow = (UserInfoRow)serializer.Deserialize(xmlChildReader);
                            if (userInfoRows == null) userInfoRows = new List<UserInfoRow>();
                            userInfoRows.Add(userRow);
                        }
                        break;
                    case "UserTransactions":
                        serializer = new XmlSerializer(typeof(UserTransactionRow));
                        xmlChildReader = reader.ReadSubtree();
                        while (xmlChildReader.ReadToFollowing("row"))
                        {
                            UserTransactionRow userRow = (UserTransactionRow)serializer.Deserialize(xmlChildReader);
                            if (userTransactionRows == null) userTransactionRows = new List<UserTransactionRow>();
                            userTransactionRows.Add(userRow);
                        }
                        break;
                }
            }

        }

        public XmlSchema GetSchema()
        {
            return (null);
        }

    }
    [XmlRoot("row")]
    public class UserInfoRow
    {
        [XmlAttribute("id")]
        public string id { get; set; }
        [XmlAttribute("Name")]
        public string Name { get; set; }
        [XmlAttribute("phone")]
        public string phone { get; set; }
    }
    [XmlRoot("row")]
    public class UserTransactionRow
    {
        [XmlAttribute("UserId")]
        public string UserId { get; set; }
        [XmlAttribute("amount")]
        public string amount { get; set; }
        [XmlAttribute("date")]
        public string date { get; set; }
    }
}

The problem is that XmlInclude expects an xsi:type attribute, which you don't have.问题是XmlInclude需要一个xsi:type属性,而您没有。

You can include it manually, by first deserializing into an `XDocument, modifying that, then deserializing your objects from that您可以手动包含它,首先反序列化为`XDocument,修改它,然后反序列化您的对象

 XmlSerializer _serializer = new XmlSerializer(typeof(document));  // always cache

 public static void Main()
 {
     var xml = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<document>
<data id=""UserInfo"">
 <rows>
   <row id=""123"" Name=""Alex"" phone=""+1234567890""></row>
   <row id=""321"" Name=""Sally"" phone=""+1234567890""></row>
 </rows>
</data>
<data id=""UserTransactions"">
 <rows>
   <row UserId=""123"" amount=""100.1"" date=""2022-07-03""></row>
   <row UserId=""123"" amount=""-100.1"" date=""2022-07-03""></row>
   <row UserId=""321"" amount=""1"" date=""2022-07-03""></row>
 </rows>
</data>
</document>
";
     var xdoc = XDocument.Parse(xml);
     AddTypeDefinition(xdoc);
     Console.WriteLine(xdoc.ToString());
     var obj = (document)_serializer.Deserialize(xdoc.CreateReader());
     Console.WriteLine(obj.data[0].rows[0].GetType().Name);
 }
 private static void AddTypeDefinition(XDocument document)
 {
     // XNamespace always converts from string implicitly
     XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
     document.Root.Add(new XAttribute(XNamespace.Xmlns + "xsi", xsi));
     foreach(var node in document.Root.Elements("data"))
     {
         string typeName;
         // decide based on "id" attribute
         if(node.Attribute("id").Value == "UserInfo")
             typeName = "UserInfoRow";
         else if(node.Attribute("id").Value == "UserInfo")
             typeName = "UserTransactionRow";
         else
             continue;

         foreach (var row in node.Element("rows").Elements("row"))
         {
             // xsi + "type" creates an XName with the namespace name
             // we have already added that declaration so becomes "xsi:type"
             row.Add(new XAttribute(xsi + "type", typeName));
         }
     }
 }

dotnetfiddle dotnetfiddle

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM