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

C# 在C中用递增的元素名反序列化XML响应#,c#,.net,xml,deserialization,C#,.net,Xml,Deserialization,我正在尝试使用ASP.NET C#使用第三方API,该API返回的结果如下面的示例所示,我被子对象的名称递增这一事实绊倒了: <Results> <Count>3</Count> <Result1> <Id>1</Id> <Property1>value</Property1> <Property2>value</Pro

我正在尝试使用ASP.NET C#使用第三方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>
这是XML的常见模式吗?有人对如何序列化有什么想法吗?我不经常使用XML(主要是JSON),所以请提前感谢

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

}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Xml;
使用System.Xml.Linq;
命名空间控制台应用程序42
{
班级计划
{
静态void Main(字符串[]参数)
{
字符串xml=
"" +
"" +
"3" +
“……财产……”+
“……财产……”+
“……财产……”+
"" +
"";
XElement xResults=XElement.Parse(xml);
Results=xResults.Elements(“Results”)。选择(x=>newresults(){
Count=(int)x.Element(“Count”),
ResultItems=x.Elements()。其中(y=>y.Name.LocalName.StartsWith(“Result”))。选择(y=>(string)y)。ToList()
}).FirstOrDefault();
}
}
公开课成绩
{
公共整数计数{get;set;}
公共列表ResultItems{get;set;}
}
}

jdweng的答案是有效的,对于你们中有选择使用它的人来说,应该接受它;但是,我的问题是数据在一个更大的XML响应中,使用XML序列化程序而不是
XElement
可以很好地处理95%的字段(另外5%是我在问题中指定的部分),因此我不想丢弃该代码,而是要实现IXmlSerializable接口

在撕下大部分头发后,我终于想出了如何针对我的情况实现
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();
    }
}
公共类结果:IXmlSerializable
{
公共整数计数{get;set;}
公共列表ResultItems{get;set;}
公开结果()
{
ResultItems=新列表();
}
公共XmlSchema GetSchema()
{
返回(空);
}
公共void ReadXml(XmlReader)
{
reader.ReadStartElement(“结果”);
如果(reader.Name==“Count”)
{
Count=reader.ReadElementContentAsInt();
}
对于(int i=Count;i>0;i--)
{
var result=新结果();
reader.ReadStartElement(“结果”+i);
result.Property1=reader.ReadElementContentAsInt();
result.Property2=reader.ReadElementContentAsString();
...
...
result.PropertyN=reader.ReadElementContentAsString();
结果添加(结果);
}
reader.ReadEndElement();
}
public void WriteXml(XmlWriter)
{
//我不需要将其写入XML,
//所以我不打算实施这个
抛出新的NotImplementedException();
}
}
首先,我调用
reader.ReadToElement()
并将元素名放在那里。当读取器被传递到
ReadXml
方法时,它位于请求结果的开头,因此您需要将其传递到要序列化的对象的开头

然后,我读取名为Count的第一个元素。我将该值放入Count属性,然后遍历所有结果。需要注意的是,必须读取结果对象的每个属性,否则会出现异常

最后,我读了结束语,继续我的生活。请让我知道您对该实施的看法,以及是否有任何改进


有一件事我不明白,我有一个results对象,而reader有一个我想要使用的方法:
reader.ReadElementContentAs(typeof(Result),null)
——这样做似乎比像我在实现中那样读取每个节点更好。有人知道怎么做吗

可以通过实现IXmlSerializable来实现。有关示例,请参见。但是您也可以使用
XDocument.Parse
来实现这一点。在我看来,这更容易处理。在SO中有几个条目可以使用
XDocument.Parse
这是一种奇怪的XML样式,反序列化非常困难,有一个冗余的
计数
,可以很容易地从数据中推断出来。根据前面的评论,我将使用类似于
XDocument.Parse(srcData).Root.Elements().Where(el=>Regex.IsMatch(el.Name,@“Result\d+”)))的内容)//etc
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();
    }
}