【问题标题】:XML to Classes via LINQ with nested listsXML to Classes 通过带有嵌套列表的 LINQ
【发布时间】:2019-07-19 09:51:06
【问题描述】:

所以我尝试使用 linq 将下面的这个 xml 代码解析到类中,但我很难获得内部列表。 xml 包含在我正在解析的 XDocument 中。

<Response>
<ResponseTransaction>
    <transaction>
        <tranId>3216</tranId>
        <tranName>TestTran01</tranName>
        <tranResultList>
            <tranResult>
                <state>Expired</state>
                <created>2019-02-23</created>
                <docList>
                    <doc id="1" name="Doc1" />
                    <doc id="2" name="Doc2" />
                    <doc id="3" name="Doc3" />
                    <doc id="4" name="Doc4" />
                </docList>
                <roleList>
                    <role role="usrRole" id="1">
                        <firstName>Jack</firstName>
                        <lastName>Daniels</lastName>
                        <email>jd@gmail.com</email>
                        <docList>
                            <doc id="1" name="Doc1" status="removed" />
                            <doc id="2" name="Doc2" status="current" />
                            <doc id="3" name="Doc3" status="current" />
                            <doc id="4" name="Doc4" status="current" />
                        </docList>
                    </role>
                </roleList>
            </tranResult>
            <tranResult>
                <state>undefined</state>
                <created>2019-02-24</created>
                <docList>
                    <doc id="1" name="Doc1" />
                    <doc id="2" name="Doc2" />
                    <doc id="3" name="Doc3" />
                    <doc id="4" name="Doc4" />
                </docList>
                <roleList>
                    <role role="usrRole" id="1">
                        <firstName>Jack</firstName>
                        <lastName>Daniels</lastName>
                        <email>jd@gmail.com</email>
                        <docList>
                            <doc id="1" name="Doc1" status="removed" />
                            <doc id="2" name="Doc2" status="current" />
                            <doc id="3" name="Doc3" status="current" />
                            <doc id="4" name="Doc4" status="current" />
                        </docList>
                    </role>
                </roleList>
            </tranResult>
            <tranResult>
                <state>Current</state>
                <created>2019-02-25</created>
                <docList>
                    <doc id="1" name="Doc1" />
                    <doc id="2" name="Doc2" />
                    <doc id="3" name="Doc3" />
                    <doc id="4" name="Doc4" />
                </docList>
                <roleList>
                    <role role="usrRole" id="1">
                        <firstName>Jack</firstName>
                        <lastName>Daniels</lastName>
                        <email>jd@gmail.com</email>
                        <docList>
                            <doc id="1" name="Doc1" status="removed" />
                            <doc id="2" name="Doc2" status="current" />
                            <doc id="3" name="Doc3" status="current" />
                            <doc id="4" name="Doc4" status="current" />
                        </docList>
                    </role>
                </roleList>
            </tranResult>
        </tranResultList>
     </transaction>
   </ResponseTransaction>
</Response>

这是我正在使用的课程。

   public class Transaction {
        public string TranId { get; set; }
        public string TranName { get; set; }
        public List<TranResult> TranResultList { get; set; }
}

public class TranResult {
        public string State { get; set; }
        public string DateCreated { get; set; }
        public List<Document> DocumentList { get; set; }
        public List<Role> RoleList { get; set; }
}

public class Document {
        public string Id { get; set; }
        public string Name { get; set; }
        public string status { get; set; }
}

public class Role {
        public string Id { get; set; }
        public string RoleName { get; set; }
        public User user { get; set; }
}

public class User {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public List<Document> DocumentList { get; set; }
}

如果此 XML 文档中没有内部列表,那么它会很简单,我只需执行一个简单的 LINQ 查询即可完成。我不确定我是否可以遍历内部列表。

感谢任何帮助。

【问题讨论】:

  • 您已经给出了 XML 和 C# 类的一个很好的示例,但并未真正展示您的解析代码在哪里。获取 XML sn-ps 没有问题——它们应该代表足够的数据来实例化您的对象。真正的绊脚石是什么?

标签: c# xml linq


【解决方案1】:

这里有一些可以使用的功能。使用 ClassinstanceFromXML 从最里面构建它,它将完成:

    public static XElement GetTransaction(XDocument xDoc)
    {
        return xDoc.Descendants("transaction").FirstOrDefault();
    }

    public static Transaction TransactionFromXML(XElement transactionXElement)
    {
        string tranId = transactionXElement.Element("tranId").Value;
        string tranName = transactionXElement.Element("tranName").Value;
        //transform all <tranResult> Xelements into Class objects
        //by passing the xml content of those tags into the TransResultFromXML selector function
        List<TranResult> transResults = transactionXElement.Element("tranResultList")?
            .Elements("tranResult")?.Select(TransResultFromXML).ToList();

        Transaction t = new Transaction()
        {
            TranId = tranId,
            TranName = tranName,
            TranResultList = transResults
        };
        return t;
    }

    public static TranResult TransResultFromXML(XElement transResultElement)
    {
        string state = transResultElement.Element("state").Value;
        string dateCreated = transResultElement.Element("created").Value;
        List<Document> docList;
        //transform all <doc> Xelements in <docList> into Class objects
        //by passing the xml content of those tags into the DocumentFromXML selector function
        docList = transResultElement.Element("docList")?
            .Elements("doc")?.Select(DocumentFromXML).ToList();
        List<Role> roleList;

        //transform all <role> Xelements in <roleList> into Class objects
        //by passing the xml content of those tags into the RoleFromXML selector function
        roleList = transResultElement.Element("roleList")?
            .Elements("role")?.Select(RoleFromXML).ToList();

        return new TranResult()
        {
            State = state,
            DateCreated = dateCreated,
            DocumentList = docList,
            RoleList = roleList
        };
    }

    public static Role RoleFromXML(XElement roleElement)
    {
        string id = roleElement.Attribute("id").Value;
        string roleName = roleElement.Attribute("role").Value;
        //A similar apttern has been used above - do same here
        List<Document> userDocList = roleElement.Element("docList")?
            .Elements("doc")?.Select(DocumentFromXML).ToList();
        User myUser = new User()
        {
            FirstName = roleElement.Element("firstName")?.Value,
            LastName = roleElement.Element("lastName")?.Value,
            Email = roleElement.Element("email")?.Value,
            DocumentList = userDocList
        };
        return new Role()
        {
            Id = id,
            RoleName = roleName,
            user = myUser
        };
    }

    public static Document DocumentFromXML(XElement docElement)
    {
        return new Document()
        {
            Id = docElement.Attribute("id").Value,
            Name = docElement.Attribute("name").Value,
            status = docElement.Attribute("status")?.Value
        };
    }

    static void Main(string[] args)
    {
        XDocument x = XDocument.Load(@"Path\To\transactions.xml");
        Transaction myTransaction = TransactionFromXML(GetTransaction(x));

        Console.WriteLine(myTransaction.TranResultList.ElementAt(1).RoleList.ElementAt(0).user.Email);

        Console.ReadLine();
    }

【讨论】:

    【解决方案2】:

    有三个问题

    1. 序列化程序区分大小写。由于您的类名和 xml 标记名的大写不匹配,您需要在类中的属性上方的方括号中添加属性
    2. 当您有序列化的数组时,您可以做以下两件事之一。首先,您可以为 xml 中的每个标签创建一个类。或者,您可以使用 XmlArray 和 XmlArrayItem 将两个标签组合成一个类。当每个 xml 标记都有一个类时,请使用 XmlElement 以及 List 对象或数组对象。如果没有 XmlElement,网络库会假定两个类(XmlArray 和 XmlArrayItem)。
    3. xml 文件中的前两个标签缺少两个类。

    见下方代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Xml.Serialization;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            const string FILENAME = @"c:\temp\test.xml";
            static void Main(string[] args)
            {
                XmlReader reader = XmlReader.Create(FILENAME);
                XmlSerializer serializer = new XmlSerializer(typeof(Response));
                Response response = (Response)serializer.Deserialize(reader);
    
            }
        }
        [XmlRoot("Response")]
        public class Response
        {
            [XmlElement("ResponseTransaction")]
            public ResponseTransaction responseTransaction { get; set; }
        }
        [XmlRoot("ResponseTransaction")]
        public class ResponseTransaction
        {
            [XmlElement("transaction")]
            public Transaction transaction { get; set; }
        }
        [XmlRoot("transaction")]
        public class Transaction
        {
            [XmlElement("tranId")]
            public string TranId { get; set; }
            [XmlElement("tranName")]
            public string TranName { get; set; }
            [XmlArray("tranResultList")]
            [XmlArrayItem("tranResult")]
            public List<TranResult> TranResultList { get; set; }
        }
    
        public class TranResult
        {
            [XmlElement("state")]
            public string State { get; set; }
            [XmlElement("created")]
            public string DateCreated { get; set; }
            [XmlArray("docList")]
            [XmlArrayItem("doc")]
            public List<Document> DocumentList { get; set; }
            [XmlArray("roleList")]
            [XmlArrayItem("role")]
            public List<Role> RoleList { get; set; }
        }
    
        public class Document
        {
            [XmlAttribute("id")]
            public string Id { get; set; }
            [XmlAttribute("name")]
            public string Name { get; set; }
            [XmlAttribute("status")]
            public string status { get; set; }
        }
    
        public class Role
        {
            [XmlAttribute("id")]
            public string Id { get; set; }
            [XmlAttribute("role")]
            public string RoleName { get; set; }
            [XmlElement("firstName")]
            public string FirstName { get; set; }
            [XmlElement("lastName")]
            public string LastName { get; set; }
            [XmlElement("email")]
            public string Email { get; set; }
            [XmlArray("docList")]
            [XmlArrayItem("doc")]
            public List<Document> DocumentList { get; set; }
        }
    }
    

    添加了类用户


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Xml.Serialization;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            const string FILENAME = @"c:\temp\test.xml";
            static void Main(string[] args)
            {
                XmlReader reader = XmlReader.Create(FILENAME);
                XmlSerializer serializer = new XmlSerializer(typeof(Response));
                Response response = (Response)serializer.Deserialize(reader);
    
            }
        }
        [XmlRoot("Response")]
        public class Response
        {
            [XmlElement("ResponseTransaction")]
            public ResponseTransaction responseTransaction { get; set; }
        }
        [XmlRoot("ResponseTransaction")]
        public class ResponseTransaction
        {
            [XmlElement("transaction")]
            public Transaction transaction { get; set; }
        }
        [XmlRoot("transaction")]
        public class Transaction
        {
            [XmlElement("tranId")]
            public string TranId { get; set; }
            [XmlElement("tranName")]
            public string TranName { get; set; }
            [XmlArray("tranResultList")]
            [XmlArrayItem("tranResult")]
            public List<TranResult> TranResultList { get; set; }
        }
    
        public class TranResult
        {
            [XmlElement("state")]
            public string State { get; set; }
            [XmlElement("created")]
            public string DateCreated { get; set; }
            [XmlArray("docList")]
            [XmlArrayItem("doc")]
            public List<Document> DocumentList { get; set; }
            [XmlArray("roleList")]
            [XmlArrayItem("role")]
            public List<Role> RoleList { get; set; }
        }
    
        public class Document
        {
            [XmlAttribute("id")]
            public string Id { get; set; }
            [XmlAttribute("name")]
            public string Name { get; set; }
            [XmlAttribute("status")]
            public string status { get; set; }
        }
    
        public class Role
        {
            private User user = new User();
            [XmlAttribute("id")]
            public string Id { get; set; }
            [XmlAttribute("role")]
            public string RoleName { get; set; }
    
            [XmlElement("firstName")]
            public string FirstName {
                get { return user.FirstName; }
                set { user.FirstName = value; }
            }
    
            [XmlElement("lastName")]
            public string LastName
            {
                get { return user.LastName; }
                set { user.LastName = value; }
            }
    
            [XmlElement("email")]
            public string Email
            {
                get { return user.Email; }
                set { user.Email = value; }
            }
    
            [XmlArray("docList")]
            [XmlArrayItem("doc")]
            public List<Document> DocumentList {
                get { return user.DocumentList; }
                set { user.DocumentList = value; } 
            }
    
        }
        public class User
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public string Email { get; set; }
            public List<Document> DocumentList { get; set; }
        }
    }
    

    【讨论】:

    • 谢谢!这种方法在我的应用程序中更有意义,因为它允许我将 xml 反序列化为“更具可读性”的类,然后尝试使用 LINQ 解析查询。
    • 赞成,因为这向我展示了属性和反序列化的方式。解释也很好!
    • 我确实注意到 User 类已被删除 - 这是一种设计选择,还是无法从原始 OP XML 中获取它?我无法让它工作。
    • 我最初只是关注 xml 文件。然后在我今天一大早发帖后,我说你可能会问用户类发生了什么,所以我想出了一个办法。然后你问了这个问题。所以我为用户添加了第二个解决方案。
    【解决方案3】:
    public static class MyMethods
    {       
        public static void XMLWrite<T>(this T obj, string PathXML) where T : class, new()
        {
    
                if (Directory.Exists(Path.GetDirectoryName(PathXML)))
                {
                    using (FileStream stream = new FileStream(PathXML, FileMode.Create))
                    using (XmlTextWriter writer = new XmlTextWriter(stream, Encoding.Unicode))
                    {
                        XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());
                        xmlSerializer.Serialize(writer, obj);
                    }
                }
        }
    
        public static T XMLRead<T>(this string PathXML) where T : class, new()
        {
                if (File.Exists(PathXML))
                {
                    XmlSerializer xmlOkuyucu = new XmlSerializer(typeof(T));
                    using (Stream okuyucu = new FileStream((PathXML), FileMode.Open))
                    {
                        return (T)xmlOkuyucu.Deserialize(okuyucu);
                    }
                }
                return default(T);
        }
     }
    

    使用通用方法,您可以编写或读取包含列表的对象。

    例子:

            object1 = MyMethods.XMLRead<YourClass>(string.Format("{0}\\{1}", locationXML, "file1.xml"));
            object2 = MyMethods.XMLRead<List<YourClass2>>(string.Format("{0}\\{1}", locationXML, "file2.xml"));
    
            object3.XMLWrite(Path.GetDirectoryName(Application.ExecutablePath) + "\\file3.xml");
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-25
      • 2018-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多