简体   繁体   English

在 C# 中使用递增的元素名称反序列化 XML 响应

[英]Deserialize XML Response with Incremented Element Names in C#

I am trying to consume a 3rd party API using ASP.NET C# that returns results as seen in the example below and I am getting tripped up on the fact that the child objects have incremented names:我正在尝试使用 ASP.NET C# 使用 3rd 方 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>

My C# class is as outlined below, and through some research I am assuming that I have to implement IXmlSerializable to handle this somehow:我的 C# 类如下所述,通过一些研究,我假设我必须实现IXmlSerializable以某种方式处理这个:

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

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

Is this a common pattern for XML and does anyone have any ideas on how to serialize this?这是 XML 的常见模式吗?有人对如何序列化它有任何想法吗? I don't work a lot with XML (mostly JSON), so thanks in advance.我很少使用 XML(主要是 JSON),所以提前致谢。

Using xml linq使用 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; }
    }

}

jdweng's answer works, and for those of you who have an option to use that should take it; jdweng 的回答有效,对于那些可以选择使用的人来说,应该接受它; however, my issue is the data is in a much larger XML response and using the xml serializer instead of XElement works really well with 95% of the fields (the other 5% being the section I specified in the question), so I don't want to jettison that code - instead, I want to implement the IXmlSerializable interface.但是,我的问题是数据在一个更大的 XML 响应中,并且使用 xml 序列化程序而不是XElement可以很好地处理 95% 的字段(另外 5% 是我在问题中指定的部分),所以我不我不想放弃该代码 - 相反,我想实现 IXmlSerializable 接口。

After tearing out most of my hair and a little help from this article , I finally figured out how to implement IXmlSerializable for my situation, and I wanted to post the answer for anyone who has a similar issue, as well as community feedback since there didn't seem to be anything on stack overflow about this:在撕掉了我的大部分头发并从本文中获得了一些帮助后,我终于想出了如何为我的情况实现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();
    }
}

First, I call reader.ReadToElement() and put the element name in there.首先,我调用reader.ReadToElement()并将元素名称放在那里。 When the reader gets passed to the ReadXml method, it is at the beginning of the request result, so you need to get it to the beginning of the object you want to serialize.当 reader 被传递给ReadXml方法时,它位于请求结果的开头,因此您需要将它传递到要序列化的对象的开头。

Then, I read the first element whose name is Count.然后,我读取了名称为 Count 的第一个元素。 I put the value in the Count property and then loop through all of the results.我将值放在 Count 属性中,然后遍历所有结果。 It is important to note that you must read every property of the result object, otherwise you will get exceptions.需要注意的是,必须读取结果对象的每个属性,否则会出现异常。

Lastly, I read the closing tag and move on with my life.最后,我阅读了结束标签并继续我的生活。 Please let me know what you think about this implementation and if there are any improvements that could be made.请让我知道您对此实现的看法,以及是否可以进行任何改进。

One thing I could not figure out is that I have a results object and the reader has a method that I want to use: reader.ReadElementContentAs(typeof(Result), null) - it seems it would be nicer to do that instead of reading each individual node as I have done in my implementation.我无法弄清楚的一件事是,我有一个结果对象,而读者有一个我想使用的方法: reader.ReadElementContentAs(typeof(Result), null) - 这样做似乎比阅读更好每个单独的节点,就像我在我的实现中所做的那样。 Does anyone know how to do that?有谁知道这是怎么做到的吗?

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

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