将XML转换为C#对象

3
我需要从这些 XML 数据中获取订单号(OrderID):
<?xml version="1.0" encoding="utf-8"?>
<GetOrdersResponse xmlns="urn:ebay:apis:eBLBaseComponents">
  <Timestamp>2015-12-10T16:12:55.184Z</Timestamp>
  <Ack>Success</Ack>
  <Version>967</Version>
  <Build>e967_core_Bundled_5642307_R1</Build>
  <OrderArray>
    <Order>
      <OrderID>865826</OrderID>
      <OrderStatus>Active</OrderStatus>
   </Order>
  </OrderArray>
</GetOrdersResponse>

我尝试过这个方法,但它没有生效。

var xDoc = XDocument.Parse(xmlResult);
var orderElements = xDoc.Elements("GetOrdersResponse").Elements("OrderArray").Elements("Order");
foreach (XElement elem in orderElements)
{
    var orderId = Convert.ToInt32(_xmlHelper.GetChildElementValue(elem, "OrderID"));
}

请给予指导。
5个回答

3

对于这样的问题,我会选择使用XmlSerializer。使用以下类:

    using System;
    using System.Xml.Serialization;
    using System.Collections.Generic;
    namespace classes
    {
        [XmlType(Namespace = "urn:ebay:apis:eBLBaseComponents")]
   public class Order
    {
        public int OrderID { get; set; }
        public string OrderStatus { get; set; }
    }

    [XmlType(Namespace = "urn:ebay:apis:eBLBaseComponents")]
    public class OrderArray
    {
        public List<Order> Orders { get; set; }
    }

    [XmlRoot(Namespace = "urn:ebay:apis:eBLBaseComponents")]
    public class GetOrdersResponse
    {
        public string Timestamp { get; set; }
        public string Ack { get; set; }
        public string Version { get; set; }
        public string Build { get; set; }
        public OrderArray OrderArray { get; set; }
    }

    }

然后将其反序列化为对象:

XmlSerializer serializer = new XmlSerializer(typeof(GetOrdersResponse ));
using (TextReader reader = new StringReader(xmlResult))
{
    GetOrdersResponse result = (GetOrdersResponse) serializer.Deserialize(reader);
}

int id=result.OrderArray.Orders.First().OrderID; //this will return ID of first object in Orders list.

1
"[XmlAttribute(AttributeName = "xmlns")] public string Xmlns { get; set; }" 看起来非常非常错误... 大多数应该是 XmlType,而不是 XmlRoot。" - Marc Gravell
1
FYI,它仍然比它需要的复杂得多 - XmlSerializer 做出了很多合理的假设,例如“命名空间由子代继承”和“元素命名为成员名称”,因此你只需要:https://gist.github.com/mgravell/1b91e0e5e6a47bdb3cff42e61281f6ce - 纯粹是 FYI。 - Marc Gravell
1
嘿,抱歉,我喜欢您的答案(我喜欢 XmlSerializer),但是如果我们假设 OrderArray 实际上是 0、1 或多个,您还可以省略整个类型( OrderArray),并只需在 GetOrdersResponse 上使用 public List<Order> OrderArray { get; set; } - Marc Gravell
1
没错,但在一个给定的例子中是不必要的。但这应该被实现,否则OrderArray将变得多余。 - tadej
1
最后,如果您使用 public int OrderID { get; set; },正确的转换将自动发生。 - Marc Gravell

2
您可以按照以下步骤操作:
XDocument xdoc = XDocument.Load("YourXMLFile");
var orderId = xdoc.Descendants("OrderID").FirstOrDefault().Value;

1
我不会期望xDoc.Elements("GetOrdersResponse")能够工作,因为它在查找默认命名空间,而这里的所有内容都在"urn:ebay:apis:eBLBaseComponents"中。因此,你需要XName告诉它至少这一点:
    var xDoc = XDocument.Parse(xmlResult);
    XNamespace ns = "urn:ebay:apis:eBLBaseComponents";
    var orderElements = xDoc.Elements(ns + "GetOrdersResponse")
            .Elements(ns + "OrderArray").Elements(ns + "Order");
    foreach (XElement elem in orderElements)
    {
        var orderId = (int)elem.Element(ns + "OrderID");
    }

(注意使用 (int) 来进行XML特定的转换)。
但是,使用XmlSerializer可能更容易,让来担心解密数据。

1

您应该使用这个示例代码

重要提示

  • 序列化类需要标记为[Serializable]属性
  • 如果类名与xml根标记不同,则将该类标记为[XmlRoot(ElementName = "XmlTagName")]属性
  • 如果序列化的类具有另一个类作为属性类型,则将此属性标记为[XmlElement("XmlTagName")]属性

示例代码

模型

      [Serializable]
        [XmlRoot(ElementName = "HardwareInfo")]
        public class Hardware
        {
            [XmlElement]
            public string cpu_name { get; set; }
            [XmlElement]
            public int ram_size { get; set; }

            [XmlElement("hard_disk")]
            public List<HardDisk> hd { get; set; }                   
        }

        [Serializable]
        [XmlRoot(ElementName = "hard_disk")]
        public class HardDisk
        {
            [XmlElement]
            public string model { get; set; }
            [XmlElement]
            public string size { get; set; }
        }

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string xmlString = @"<HardwareInfo>
                                  <cpu_name> ABC Pentium xyz</cpu_name>
                                  <ram_size> 123 </ram_size>
                                  <hard_disk>
                                    <model>Toshiba XYZ</model>
                                    <size> 123 GB </size>
                                  </hard_disk>
                                  <hard_disk>
                                    <model>Logitech XYZ</model>
                                    <size> 99 GB </size>
                                  </hard_disk>
                                </HardwareInfo>";

            var result = DeSerialization<Hardware>(xmlString);
        }

        static T DeSerialization<T>(string xmlStrig) where T : class
        {
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));                        
            using (StringReader sReader = new StringReader(xmlStrig))
            {
                return (T)xmlSerializer.Deserialize(sReader);
            }
        }
    }          
}

1
抱歉,但这只是没有任何帮助的… XmlSerializer 根本不关心 [Serializable]。问题中最复杂的因素是命名空间,而此答案并未解决;而且:它与问题根本不相关。 - Marc Gravell

0

如果你将xml数据保存在文件中,你也可以使用XmlDocumentXmlNodeList来获取它。

        XmlDocument doc = new XmlDocument();
        doc.Load("your XML File Name with extension");
        XmlNodeList elemList = doc.GetElementsByTagName("OrderID");
        for (int i = 0; i < elemList.Count; i++)
        {
            Console.WriteLine(elemList[i].InnerText);
        }

这个方法可以运行,但是GetElementsByTagName几乎总是解决问题的可怕选择 - 容易出现错误等。问题的主要复杂性在于命名空间,可以通过XDocumentXmlDocument的常规查询方法完美地解决,而不需要使用GetElementsByTagName这种核心选项。 - Marc Gravell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接