使用 C# 创建对象解析 XML

Using C# to create objects parsing XML

我花了 1.5 天时间尝试创建一个对象来解析 XML:

<EnvelopeStatus>
 <RecipientStatuses>
  <RecipientStatus>
   <Type>Signer</Type>
            <Email>johndoe@gmail.com</Email>
            <UserName>Doe, John</UserName>            
            <Status>Completed</Status>            
            <CustomFields>
               <CustomField>1001</CustomField>
            </CustomFields>
  </RecipientStatus>
  <RecipientStatus>
   <Type>Signer</Type>
            <Email>maryjane@gmail.com</Email>
            <UserName>Jane, Mary</UserName>            
            <Status>Sent</Status>            
            <CustomFields>
               <CustomField>1002</CustomField>
            </CustomFields>
  </RecipientStatus>
 </RecipientStatuses>
 <Status>Completed</Status>
 <Id>25b9b7e8-c4c0-4711-a80c-24663f0dc6ed</Id>
 <CustomFields>
  <CustomField>
   <Name>Url</Name>            
            <Required>False</Required>
            <Value>http://google.com</Value>
         </CustomField>
         <CustomField>
            <Name>List</Name>            
            <Required>False</Required>
            <Value>Blue</Value>
         </CustomField>
         <CustomField>
            <Name>ItemId</Name>            
            <Required>False</Required>
            <Value>2</Value>
         </CustomField>
</EnvelopeStatus>

RecipientStatuses 可以包含多个 RecipientStatus。 RecipientStatus 内部有一组 CustomFields。理想情况下,单个 CustomField 将上升到与类型、电子邮件、用户名等相同的级别。

Status、ID在EnvelopeStatus下,也包含了CustomFields的集合。此集合中真正需要的唯一节点是 'Value' 节点,因此理论上,Value 可以上升到与 Status 和 Id 相同的级别。

我尝试了很多不同的事情,现在回到原点。有没有办法解析这个 xml,以便设置这些 类 中的属性:

public class Request
{
    public string Id { get; set; }
    public string Status { get; set; }
    public string Url { get; set; }
    public string List { get; set; }
    public string ItemId { get; set; }
    public List<Signer> Signers { get; set; }
}
public class Signer
{
    public string Type { get; set; }    
    public string Email { get; set; }
    public string UserName { get; set; }
 public int UserId { get; set; }
}

你可以这样做:

var doc = XElement.Load("path to your XML file");
var req = new Request
{
    Id = (string)doc.Element("Id"),
    Status = (string)doc.Element("Status"),
    Url = (string)doc.Element("CustomFields")
                     .Elements("CustomFields")
                     .Where(cf => (string)cf.Element("Name") == "Url")
                     .Select(cf => (string)cf.Element("Value"))
                     .First(),
    //Follow `Url` example above to populate `List` and `ItemId` properties
    Signers = doc.Elements("RecipientStatuses")
                 .Elements("RecipientStatus")
                 .Select(o => new Signer
                 {
                     Type = (string)o.Element("Type"),
                     //Follow `Type` example above to populate `Email` and `UserName` properties
                     UserId = (int)o.Element("CustomFields").Element("CustomField")
                 })
                 .ToList()
};

使用 XPath 表达式的替代形式:

var doc = XElement.Load("path to your XML file");
var req = new Request
{
    Id = (string)doc.XPathSelectElement("Id"),
    Status = (string)doc.XPathSelectElement("Status"),
    Url = (string)doc.XPathSelectElement("CustomFields/CustomFields[Name='Url']/Value"),
    //Follow `Url` example above to populate `List` and `ItemId` properties
    Signers = doc.XPathSelectElements("RecipientStatuses/RecipientStatus")
                 .Select(o => new Signer
                 {
                     Type = (string)o.Element("Type"),
                     //Follow `Type` example above to populate `Email` and `UserName` properties
                     UserId = (int)o.XPathSelectElement("CustomFields/CustomField")
                 })
                 .ToList()
};

尝试单个查询

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);
            Request request = doc.Elements("EnvelopeStatus").Select(x => new  Request() {
                Id = (string)x.Element("Id"),
                Status = (string)x.Element("Status"),
                Url = (string)x.Descendants("CustomField").Where(y => (string)y.Descendants("Name").FirstOrDefault() == "Url").Select(z => z.Element("Value")).FirstOrDefault(),
                ItemId = (int)x.Descendants("CustomField").Where(y => (string)y.Descendants("Name").FirstOrDefault() == "ItemId").Select(z => z.Element("Value")).FirstOrDefault(),
                List = (string)x.Descendants("CustomField").Where(y => (string)y.Descendants("Name").FirstOrDefault() == "List").Select(z => z.Element("Value")).FirstOrDefault(),
                Signers = x.Descendants("RecipientStatus").Select(y => new Signer() {
                    Type = (string)y.Descendants("Type").FirstOrDefault(),
                    Email = (string)y.Descendants("Email").FirstOrDefault(),
                    UserName = (string)y.Descendants("UserName").FirstOrDefault(),
                    UserId = (int)y.Descendants("CustomField").FirstOrDefault()
                }).ToList()
            }).FirstOrDefault();
        }
    }
    public class Request
    {
        public string Id { get; set; }
        public string Status { get; set; }
        public string Url { get; set; }
        public string List { get; set; }
        public int ItemId { get; set; }
        public List<Signer> Signers { get; set; }
    }
    public class Signer
    {
        public string Type { get; set; }
        public string Email { get; set; }
        public string UserName { get; set; }
        public int UserId { get; set; }
    }
}