0

编辑:万一有人来这里寻找一个解决方案 - 下面的代码已更新,现在可以正确感谢接受的答案XML反序列化错误 - 意外“结束元素”


使用C#针对.NET 4.5.3,我试图将一个Web API REST XML响应反序列化为一个C#类实例。

我的问题是:如何修复此代码,以便它完成它应该执行的操作 - 正确地将XML响应序列化为C#类实例。

由于我已经添加“IsRequired =真”的属性,则抛出异常:

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

谢谢。

+2

这是无效的XML,是吗?'xmlns'是...乱码?这几乎可以肯定与xml命名空间有关。 ''与''或''不一样。我猜你的意思是'xmlns =“urn:expasy:scanprosite”'?要么...? –

+0

@MarcGravell我已将XML粘贴到Visual Studio中,以缩进它的堆栈溢出。自动格式化必须改变一些文本。我现在已经重新粘贴了。感谢您指出了这一点。 – Aalawlx

回答

2

您的类包含数据约定属性和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[] matchXmlElement

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

这样做我后我能够读取您的.xml文件中给出的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; 
    } 
} 
+0

我已经提出了两项​​建议 - 但是我仍然收到相同的例外情况?如果你有它的工作 - 有没有可能你可以粘贴整个代码,或者你有任何其他建议?谢谢 – Aalawlx

+0

我以为你的问题是没有读取匹配数组?在复制课程并调试它们之后,您添加了“IsRequired”。现在我必须重新开始? – dbc

+0

是的,没有读取匹配数组,但是也没有读取任何属性。但是,进行建议的更改不会使匹配数组读取。只是这本身就是一种改进。 – Aalawlx