【问题标题】:Deserialize XML Response with Incremented Element Names in C#在 C# 中使用递增的元素名称反序列化 XML 响应
【发布时间】:2017-01-13 17:43:03
【问题描述】:

我正在尝试使用 ASP.NET C# 来使用第 3 方 API,该 API 返回的结果如下例所示,我被子对象的名称递增的事实绊倒了:

<Results>
    <Count>3</Count>
    <Result1>
        <Id>1</Id>
        <Property1>value</Property1>
        <Property2>value</Property2>
        ...
        <PropertyN>value</PropertyN>
    </Result1>
    <Result2>...properties...</Result2>
    <Result3>...properties...</Result3>
</Results>

我的 C# 类如下所述,通过一些研究,我假设我必须实现 IXmlSerializable 以某种方式处理这个问题:

public class Results : IXmlSerializable
{
    [XmlElement("Count")]
    public int Count { get; set; }

    public List<Result> ResultItems { get; set; }
}

这是 XML 的常见模式吗?有人对如何序列化它有任何想法吗?我不经常使用 XML(主要是 JSON),所以在此先感谢。

【问题讨论】:

  • 您可以通过实现 IXmlSerializable 来实现。有关示例,请参阅How to Implement IXmlSerializable Correctly。但您也可以为此使用XDocument.Parse。在我看来,它更容易处理。 SO中有几个条目可以使用XDocument.Parse
  • 这是一种奇怪的 XML 风格,反序列化很痛苦,有一个多余的Count,可以很容易地从数据中推断出来。根据之前的 cmets,我会选择 XDocument.Parse(srcData).Root.Elements().Where(el=&gt;Regex.IsMatch(el.Name,@"Result\d+"))...//etc

标签: c# .net xml deserialization


【解决方案1】:

使用 xml linq

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

namespace ConsoleApplication42
{
    class Program
    {
        static void Main(string[] args)
        {
            string xml =
                "<Root>" +
                "<Results>" +
                    "<Count>3</Count>" +
                    "<Result1>...properties...</Result1>" +
                    "<Result2>...properties...</Result2>" +
                    "<Result3>...properties...</Result3>" +
                "</Results>" +
                "</Root>";

            XElement xResults = XElement.Parse(xml);

            Results results = xResults.Elements("Results").Select(x => new Results() {
                Count = (int)x.Element("Count"),
                ResultItems = x.Elements().Where(y => y.Name.LocalName.StartsWith("Result")).Select(y => (string)y).ToList()
            }).FirstOrDefault();

        }


    }
    public class Results
    {

        public int Count { get; set; }

        public List<string> ResultItems { get; set; }
    }

}

【讨论】:

    【解决方案2】:

    jdweng 的答案有效,对于那些可以选择使用它的人来说,应该接受它;但是,我的问题是数据位于更大的 XML 响应中,并且使用 xml 序列化程序而不是 XElement 非常适用于 95% 的字段(另外 5% 是我在问题中指定的部分),所以我不想放弃该代码 - 相反,我想实现 IXmlSerializable 接口。

    在撕掉了我的大部分头发and a little help from this article 之后,我终于想出了如何针对我的情况实施IXmlSerializable,我想为有类似问题的任何人发布答案,以及从那里获得社区反馈似乎没有关于堆栈溢出的任何内容:

    public class Results : IXmlSerializable
    {
        public int Count { get; set; }
    
        public List<Result> ResultItems { get; set; }
    
        public Results()
        {
            ResultItems = new List<Result>();
        }
    
        public XmlSchema GetSchema()
        {
            return (null);
        }
    
        public void ReadXml(XmlReader reader)
        {
            reader.ReadStartElement("Results");
    
            if(reader.Name == "Count")
            {
                Count = reader.ReadElementContentAsInt();
            }
    
            for (int i = Count; i > 0; i--)
            {
                var result = new Result();
                reader.ReadStartElement("Result" + i);
    
                result.Property1 = reader.ReadElementContentAsInt();
                result.Property2 = reader.ReadElementContentAsString();
                ...
                ...
                result.PropertyN = reader.ReadElementContentAsString();
    
                ResultItems.Add(result);
            }
    
            reader.ReadEndElement();
        }
    
        public void WriteXml(XmlWriter writer)
        {
            //I don't ever need to write this to XML, 
            //so I'm not going to implement this
            throw new NotImplementedException();
        }
    }
    

    首先,我调用reader.ReadToElement() 并将元素名称放入其中。当读取器被传递给ReadXml 方法时,它位于请求结果的开始,因此您需要将其带到您要序列化的对象的开头。

    然后,我读取了名为 Count 的第一个元素。我将值放在 Count 属性中,然后遍历所有结果。请务必注意,您必须阅读结果对象的 每个 属性,否则会出现异常。

    最后,我阅读了结束标签并继续我的生活。请让我知道您对此实施的看法以及是否可以进行任何改进。

    我想不通的一件事是我有一个结果对象,而读者有一个我想使用的方法:reader.ReadElementContentAs(typeof(Result), null) - 这样做似乎比像我一样读取每个单独的节点更好在我的实施中已经完成。有谁知道这是怎么做到的吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-12
      • 1970-01-01
      • 1970-01-01
      • 2011-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多