【问题标题】:XML Deserialization Error - unexpected 'EndElement'XML 反序列化错误 - 意外的“EndElement”
【发布时间】:2015-01-12 22:09:48
【问题描述】:

编辑:如果有人来这里寻找解决方案 - 下面的代码已经更新,现在由于接受的答案可以正常工作


使用面向 .NET 4.5.3 的 C#,我正在尝试将 Web API REST XML 响应反序列化为 C# 类实例。

我的问题是:我怎样才能修复这段代码,以便它完成它应该做的事情 - 正确地将 XML 响应反序列化到 C# 类实例。

由于我在属性中添加了“IsRequired = true”,因此引发了异常:

Message: Error in line 1 position 226. 'EndElement' 'matchset' from namespace 'urn:expasy:scanprosite' is not expected. Expecting element 'n_match'.

Source: System.Runtime.Serialization

StackTrace: 
at System.Runtime.Serialization.XmlObjectSerializerReadContext.ThrowRequiredMemberMissingException(XmlReaderDelegator xmlReader, Int32 memberIndex, Int32 requiredIndex, XmlDictionaryString[] memberNames)
at ReadmatchsetFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )
at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)
at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract)
at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, String name, String ns)
at System.Runtime.Serialization.DataContractSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.DataContractSerializer.ReadObject(XmlReader reader)
at System.Net.Http.Formatting.XmlMediaTypeFormatter.ReadFromStream(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
at System.Net.Http.Formatting.XmlMediaTypeFormatter.ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Net.Http.HttpContentExtensions.<ReadAsAsyncCore>d__0`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at ConsoleApplication4.Prosite.<XmlDeserialize>d__1.MoveNext() in C:\Users\Aaron\Documents\Visual Studio 14\Projects\ConsoleApplication4\ConsoleApplication4\Prosite.cs:line 22

这是程序到控制台窗口的输出(没有设置 IsRequired):

n_match:
n_seq:
matchset.match.length: 0

这里是HTTP请求和反序列化代码:

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace ConsoleApplication4
{
    public static class Prosite
    {
        public static async Task<string> GetPrositeXML()
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("http://www.expasy.org/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));

                // HTTP GET
                HttpResponseMessage response = await client.GetAsync("cgi-bin/prosite/PSScan.cgi?seq=ENTK_HUMAN&output=xml");
                if (response.IsSuccessStatusCode)
                {
                    return await response.Content.ReadAsStringAsync();//AsAsync<matchset>();
                }
            }

            return null;
        }
    }
}

这是控制台应用程序代码:

using System;
using System.Diagnostics;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            var matchsetTask = Prosite.GetPrositeXML();

            var xmlString = matchsetTask.Result;

            var matchset = xmlString.LoadFromXML<matchset>();

            if (matchset != null)
            {
                Console.WriteLine("n_match: " + matchset.n_match);
                Console.WriteLine("n_seq: " + matchset.n_seq);
                Console.WriteLine("matchset.match.length: " + matchset.match.Length);

                foreach (var match in matchset.match)
                {
                    Console.WriteLine("level: " + match.level);
                    Console.WriteLine("level_tag: " + match.level_tag);
                    Console.WriteLine("score: " + match.score);
                    Console.WriteLine("sequence_ac: " + match.sequence_ac);
                    Console.WriteLine("sequence_db: " + match.sequence_db);
                    Console.WriteLine("sequence_id: " + match.sequence_id);
                    Console.WriteLine("signature_ac: " + match.signature_ac);
                    Console.WriteLine("signature_id: " + match.signature_id);
                    Console.WriteLine("start: " + match.start);
                    Console.WriteLine("stop: " + match.stop);
                    Console.WriteLine("");
                }
            }

            Console.ReadKey();
        }
    }
}

这是根节点“matchset”模型的类:

using System;
using System.Runtime.Serialization;
using System.Xml.Serialization;
using System.ServiceModel;

namespace ConsoleApplication4
{
    [Serializable]
    [XmlSerializerFormat]
    [DataContract(Name = "matchset", Namespace = "urn:expasy:scanprosite")]
    [XmlRoot(ElementName = "matchset", Namespace = "urn:expasy:scanprosite")]
    public class matchset
    {
        [DataMember(Name = "match")]
        [XmlElement("match")]
        public match[] match;

        [DataMember(Name = "n_match", IsRequired = true)]
        [XmlAttribute("n_match")]
        public string n_match;

        [DataMember(Name = "n_seq", IsRequired = true)]
        [XmlAttribute("n_seq")]
        public string n_seq;
    }
}

这是“匹配”模型的代码:

using System;
using System.Runtime.Serialization;
using System.Xml.Serialization;
using System.ServiceModel;

namespace ConsoleApplication4
{
    [Serializable]
    [XmlSerializerFormat]
    [DataContract(Name = "match", Namespace = "")]
    public class match
    {
        [DataMember(Name = "sequence_ac")]
        [XmlElement("sequence_ac")]
        public string sequence_ac;

        [DataMember(Name = "sequence_id")]
        [XmlElement("sequence_id")]
        public string sequence_id;

        [DataMember(Name = "sequence_db")]
        [XmlElement("sequence_db")]
        public string sequence_db;

        [DataMember(Name = "start")]
        [XmlElement("start")]
        public string start;

        [DataMember(Name = "stop")]
        [XmlElement("stop")]
        public string stop;

        [DataMember(Name = "signature_ac")]
        [XmlElement("signature_ac")]
        public string signature_ac;

        [DataMember(Name = "signature_id")]
        [XmlElement("signature_id")]
        public string signature_id;

        [DataMember(Name = "level_tag")]
        [XmlElement("level_tag")]
        public string level_tag;

        [DataMember(Name = "score")]
        [XmlElement("score")]
        public string score;

        [DataMember(Name = "level")]
        [XmlElement("level")]
        public string level;
    }
}

这是正在反序列化的 XML:

<?xml version="1.0" encoding="UTF-8"?>
<matchset xmlns="urn:expasy:scanprosite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:expasy:scanprosite http://expasy.org/tools/scanprosite/scanprosite.xsd" n_match="13" n_seq="1">
    <match>
        <sequence_ac>P98073</sequence_ac>
        <sequence_id>ENTK_HUMAN</sequence_id>
        <sequence_db>sp</sequence_db>
        <start>54</start>
        <stop>169</stop>
        <signature_ac>PS50024</signature_ac>
        <signature_id>SEA</signature_id>
        <score>32.979</score>
        <level>0</level>
    </match>
    <match>
        <sequence_ac>P98073</sequence_ac>
        <sequence_id>ENTK_HUMAN</sequence_id>
        <sequence_db>sp</sequence_db>
        <start>183</start>
        <stop>222</stop>
        <signature_ac>PS50068</signature_ac>
        <signature_id>LDLRA_2</signature_id>
        <score>10.75</score>
        <level>0</level>
    </match>
    <match>
        <sequence_ac>P98073</sequence_ac>
        <sequence_id>ENTK_HUMAN</sequence_id>
        <sequence_db>sp</sequence_db>
        <start>197</start>
        <stop>221</stop>
        <signature_ac>PS01209</signature_ac>
        <signature_id>LDLRA_1</signature_id>
        <level_tag>(0)</level_tag>
    </match>
    <match>
        <sequence_ac>P98073</sequence_ac>
        <sequence_id>ENTK_HUMAN</sequence_id>
        <sequence_db>sp</sequence_db>
        <start>225</start>
        <stop>334</stop>
        <signature_ac>PS01180</signature_ac>
        <signature_id>CUB</signature_id>
        <score>13.293</score>
        <level>0</level>
    </match>
    <match>
        <sequence_ac>P98073</sequence_ac>
        <sequence_id>ENTK_HUMAN</sequence_id>
        <sequence_db>sp</sequence_db>
        <start>345</start>
        <stop>504</stop>
        <signature_ac>PS50060</signature_ac>
        <signature_id>MAM_2</signature_id>
        <score>42.203</score>
        <level>0</level>
    </match>
    <match>
        <sequence_ac>P98073</sequence_ac>
        <sequence_id>ENTK_HUMAN</sequence_id>
        <sequence_db>sp</sequence_db>
        <start>391</start>
        <stop>431</stop>
        <signature_ac>PS00740</signature_ac>
        <signature_id>MAM_1</signature_id>
        <level_tag>(0)</level_tag>
    </match>
    <match>
        <sequence_ac>P98073</sequence_ac>
        <sequence_id>ENTK_HUMAN</sequence_id>
        <sequence_db>sp</sequence_db>
        <start>524</start>
        <stop>634</stop>
        <signature_ac>PS01180</signature_ac>
        <signature_id>CUB</signature_id>
        <score>17.206</score>
        <level>0</level>
    </match>
    <match>
        <sequence_ac>P98073</sequence_ac>
        <sequence_id>ENTK_HUMAN</sequence_id>
        <sequence_db>sp</sequence_db>
        <start>642</start>
        <stop>678</stop>
        <signature_ac>PS50068</signature_ac>
        <signature_id>LDLRA_2</signature_id>
        <score>13.3</score>
        <level>0</level>
    </match>
    <match>
        <sequence_ac>P98073</sequence_ac>
        <sequence_id>ENTK_HUMAN</sequence_id>
        <sequence_db>sp</sequence_db>
        <start>655</start>
        <stop>677</stop>
        <signature_ac>PS01209</signature_ac>
        <signature_id>LDLRA_1</signature_id>
        <level_tag>(0)</level_tag>
    </match>
    <match>
        <sequence_ac>P98073</sequence_ac>
        <sequence_id>ENTK_HUMAN</sequence_id>
        <sequence_db>sp</sequence_db>
        <start>678</start>
        <stop>788</stop>
        <signature_ac>PS50287</signature_ac>
        <signature_id>SRCR_2</signature_id>
        <score>16.02</score>
        <level>0</level>
    </match>
    <match>
        <sequence_ac>P98073</sequence_ac>
        <sequence_id>ENTK_HUMAN</sequence_id>
        <sequence_db>sp</sequence_db>
        <start>785</start>
        <stop>1019</stop>
        <signature_ac>PS50240</signature_ac>
        <signature_id>TRYPSIN_DOM</signature_id>
        <score>39.104</score>
        <level>0</level>
    </match>
    <match>
        <sequence_ac>P98073</sequence_ac>
        <sequence_id>ENTK_HUMAN</sequence_id>
        <sequence_db>sp</sequence_db>
        <start>821</start>
        <stop>826</stop>
        <signature_ac>PS00134</signature_ac>
        <signature_id>TRYPSIN_HIS</signature_id>
        <level_tag>(0)</level_tag>
    </match>
    <match>
        <sequence_ac>P98073</sequence_ac>
        <sequence_id>ENTK_HUMAN</sequence_id>
        <sequence_db>sp</sequence_db>
        <start>965</start>
        <stop>976</stop>
        <signature_ac>PS00135</signature_ac>
        <signature_id>TRYPSIN_SER</signature_id>
        <level_tag>(0)</level_tag>
    </match>
</matchset>

@dbc 在接受的答案中提供的 XmlSerializationHelper 类:

using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace ConsoleApplication4
{
    public static class XmlSerializationHelper
    {
        public static string GetXml<T>(T obj, XmlSerializer serializer, bool omitStandardNamespaces)
        {
            using (var textWriter = new StringWriter())
            {
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;        // For cosmetic purposes.
                settings.IndentChars = "    "; // For cosmetic purposes.
                using (var xmlWriter = XmlWriter.Create(textWriter, settings))
                {
                    if (omitStandardNamespaces)
                    {
                        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                        ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
                        serializer.Serialize(xmlWriter, obj, ns);
                    }
                    else
                    {
                        serializer.Serialize(xmlWriter, obj);
                    }
                }
                return textWriter.ToString();
            }
        }

        public static string GetXml<T>(this T obj, XmlSerializer serializer)
        {
            return GetXml(obj, serializer, false);
        }

        public static string GetXml<T>(this T obj, bool omitNamespace)
        {
            XmlSerializer serializer = new XmlSerializer(obj.GetType());
            return GetXml(obj, serializer, omitNamespace);
        }

        public static string GetXml<T>(this T obj)
        {
            return GetXml(obj, false);
        }

        public static T LoadFromXML<T>(this string xmlString)
        {
            return xmlString.LoadFromXML<T>(new XmlSerializer(typeof(T)));
        }

        public static T LoadFromXML<T>(this string xmlString, XmlSerializer serial)
        {
            T returnValue = default(T);

            using (StringReader reader = new StringReader(xmlString))
            {
                object result = serial.Deserialize(reader);
                if (result is T)
                {
                    returnValue = (T)result;
                }
            }
            return returnValue;
        }
    }
}

谢谢。

【问题讨论】:

  • 那不是有效的 xml,是吗? xmlns 是……胡言乱语?这几乎可以肯定与 xml 命名空间相关。 &lt;foo&gt;&lt;alias:foo&gt;&lt;foo xmlns="urn"&gt; 不同。我猜你的意思是 xmlns="urn:expasy:scanprosite" ?还是...?
  • @MarcGravell 我已将 XML 粘贴到 Visual Studio 中以制表符缩进它以供 Stack Overflow 使用。自动格式化一定改变了一些文本。我现在重新粘贴了。感谢您指出这一点。

标签: c# xml deserialization xmlserializer datacontractserializer


【解决方案1】:

您的类包含数据协定属性和XmlSerializer 属性的混合。我将假设您正在使用XmlSerializer,因为应用了属性[XmlSerializerFormat]。在这种情况下,您需要:

  1. XmlRoot 属性放回matchset

    [Serializable]
    [XmlSerializerFormat]
    [DataContract(Name = "matchset", Namespace = "urn:expasy:scanprosite")]
    [XmlRoot(ElementName = "matchset", Namespace = "urn:expasy:scanprosite")]
    public class matchset
    {
    
  2. public match[] match 更改为XmlElement

        [DataMember(Name = "match")]
        [XmlElement("match")]
        public match[] match
        {
            get { return this.matchField; }
            set { this.matchField = value; }
        }
    

这样做后,我可以读取您帖子中给出的 xml 字符串。

答案是基于您的原始课程而不是您修改的课程。以下是我的测试方法:

public static class TestMatchSet
{
    public static void Test()
    {
        var xml = XmlProvider.GetXml(); // Returns the long XML string from the post.
        var matchSet = XmlSerializationHelper.LoadFromXML<matchset>(xml);

        Debug.WriteLine(matchSet.GetXml());
    }
}

public static class XmlSerializationHelper
{
    public static string GetXml<T>(T obj, XmlSerializer serializer, bool omitStandardNamespaces)
    {
        using (var textWriter = new StringWriter())
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;        // For cosmetic purposes.
            settings.IndentChars = "    "; // For cosmetic purposes.
            using (var xmlWriter = XmlWriter.Create(textWriter, settings))
            {
                if (omitStandardNamespaces)
                {
                    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                    ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
                    serializer.Serialize(xmlWriter, obj, ns);
                }
                else
                {
                    serializer.Serialize(xmlWriter, obj);
                }
            }
            return textWriter.ToString();
        }
    }

    public static string GetXml<T>(this T obj, XmlSerializer serializer)
    {
        return GetXml(obj, serializer, false);
    }

    public static string GetXml<T>(this T obj, bool omitNamespace)
    {
        XmlSerializer serializer = new XmlSerializer(obj.GetType());
        return GetXml(obj, serializer, omitNamespace);
    }

    public static string GetXml<T>(this T obj)
    {
        return GetXml(obj, false);
    }

    public static T LoadFromXML<T>(this string xmlString)
    {
        return xmlString.LoadFromXML<T>(new XmlSerializer(typeof(T)));
    }

    public static T LoadFromXML<T>(this string xmlString, XmlSerializer serial)
    {
        T returnValue = default(T);

        using (StringReader reader = new StringReader(xmlString))
        {
            object result = serial.Deserialize(reader);
            if (result is T)
            {
                returnValue = (T)result;
            }
        }
        return returnValue;
    }
}

【讨论】:

  • 我已经进行了您建议的两项更改 - 但是我仍然收到相同的异常?如果你有它的工作 - 你有没有机会粘贴整个代码或者你有任何其他建议吗?谢谢
  • 我以为你的问题是没有读取匹配数组?在我复制你的类并调试它们之后,你添加了“IsRequired”。现在我必须重新开始?
  • 是的,没有读取匹配数组,但也没有读取任何属性。但是,进行您建议的更改并没有读取匹配数组。仅此本身就是一种改进。
  • 在您的代码的帮助下,我已经解决了这个问题,非常感谢,解决了几个小时的头痛问题!
  • 我将 response.Content.ReadAsAsync() 更改为 response.Content.ReadAsStringAsync() 并将 XML 传递给您的 XmlSerializationHelper 类,它工作了!我还将上面的代码更新为工作版本。再次感谢!
猜你喜欢
  • 2013-02-19
  • 2015-01-11
  • 2014-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-04
  • 2011-08-09
  • 2010-10-17
相关资源
最近更新 更多