" <user xmlns=''> was not expected." 反序列化Twitter XML

272

我正在通过OAuth从Twitter拉取XML。

我正在向http://twitter.com/account/verify_credentials.xml发出请求,它返回以下XML:

<?xml version="1.0" encoding="UTF-8"?>
<user>
  <id>16434938</id>
  <name>Lloyd Sparkes</name>
  <screen_name>lloydsparkes</screen_name>
  <location>Hockley, Essex, UK</location>
  <description>Student</description>
  <profile_image_url>http://a3.twimg.com/profile_images/351849613/twitterProfilePhoto_normal.jpg</profile_image_url>
  <url>http://www.lloydsparkes.co.uk</url>
  <protected>false</protected>
  <followers_count>115</followers_count>
  <profile_background_color>9fdaf4</profile_background_color>
  <profile_text_color>000000</profile_text_color>
  <profile_link_color>220f7b</profile_link_color>
  <profile_sidebar_fill_color>FFF7CC</profile_sidebar_fill_color>
  <profile_sidebar_border_color>F2E195</profile_sidebar_border_color>
  <friends_count>87</friends_count>
  <created_at>Wed Sep 24 14:26:09 +0000 2008</created_at>
  <favourites_count>0</favourites_count>
  <utc_offset>0</utc_offset>
  <time_zone>London</time_zone>
  <profile_background_image_url>http://s.twimg.com/a/1255366924/images/themes/theme12/bg.gif</profile_background_image_url>
  <profile_background_tile>false</profile_background_tile>
  <statuses_count>1965</statuses_count>
  <notifications>false</notifications>
  <geo_enabled>false</geo_enabled>
  <verified>false</verified>
  <following>false</following>
  <status>
    <created_at>Mon Oct 12 19:23:47 +0000 2009</created_at>
    <id>4815268670</id>
    <text>&#187; @alexmuller your kidding? it should all be &quot;black tie&quot; dress code</text>
    <source>&lt;a href=&quot;http://code.google.com/p/wittytwitter/&quot; rel=&quot;nofollow&quot;&gt;Witty&lt;/a&gt;</source>
    <truncated>false</truncated>
    <in_reply_to_status_id>4815131457</in_reply_to_status_id>
    <in_reply_to_user_id>8645442</in_reply_to_user_id>
    <favorited>false</favorited>
    <in_reply_to_screen_name>alexmuller</in_reply_to_screen_name>
    <geo/>
  </status>
</user>

我正在使用以下代码进行反序列化:

    public User VerifyCredentials()
    {
        string url = "http://twitter.com/account/verify_credentials.xml";
        string xml = _oauth.oAuthWebRequestAsString(oAuthTwitter.Method.GET, url, null);

        XmlSerializer xs = new XmlSerializer(typeof(User),"");

        MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xml));

        return (User)xs.Deserialize(ms);
    }

我有以下代码定义了User类:

 [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class User
{

    [XmlElement(ElementName = "id")]       
    public long Id { get; set; }

    [XmlElement(ElementName = "name")] 
    public string Name { get; set; }

    [XmlElement(ElementName = "screen_name")]       
    public string ScreenName { get; set; }

    [XmlElement(ElementName = "location")]       
    public string Location { get; set; }

    [XmlElement(ElementName = "description")]      
    public string Description { get; set; }

    [XmlElement(ElementName = "profile_image_url")]      
    public string ProfileImageUrl { get; set; }

    [XmlElement(ElementName = "url")]       
    public string Url { get; set; }

    [XmlElement(ElementName = "protected")]      
    public bool Protected { get; set; }

    [XmlElement(ElementName = "followers_count")]      
    public int FollowerCount { get; set; }

    [XmlElement(ElementName = "profile_background_color")]       
    public string ProfileBackgroundColor { get; set; }

    [XmlElement(ElementName = "profile_text_color")]       
    public string ProfileTextColor { get; set; }

    [XmlElement(ElementName = "profile_link_color")]       
    public string ProfileLinkColor { get; set; }

    [XmlElement(ElementName = "profile_sidebar_fill_color")]       
    public string ProfileSidebarFillColor { get; set; }

    [XmlElement(ElementName = "profile_sidebar_border_color")]      
    public string ProfileSidebarBorderColor { get; set; }

    [XmlElement(ElementName = "friends_count")]     
    public int FriendsCount { get; set; }

    [XmlElement(ElementName = "created_at")]     
    public string CreatedAt { get; set; }

    [XmlElement(ElementName = "favourties_count")]      
    public int FavouritesCount { get; set; }

    [XmlElement(ElementName = "utc_offset")]      
    public int UtcOffset { get; set; }

    [XmlElement(ElementName = "time_zone")]       
    public string Timezone { get; set; }

    [XmlElement(ElementName = "profile_background_image_url")]        
    public string ProfileBackgroundImageUrl { get; set; }

    [XmlElement(ElementName = "profile_background_tile")]        
    public bool ProfileBackgroundTile { get; set; }

    [XmlElement(ElementName = "statuese_count")]        
    public int StatusesCount { get; set; }

    [XmlElement(ElementName = "notifications")]       
    public string Notifications { get; set; }

    [XmlElement(ElementName = "geo_enabled")]       
    public bool GeoEnabled { get; set; }

    [XmlElement(ElementName = "Verified")]        
    public bool Verified { get; set; }

    [XmlElement(ElementName = "following")]
    public string Following { get; set; }

    [XmlElement(ElementName = "status", IsNullable=true)]
    public Status CurrentStatus { get; set; }

}

但是当它对上述XML进行反序列化时,应用程序会抛出以下异常:

$exception {"XML文档中存在错误 (2, 2)。"} System.Exception {System.InvalidOperationException}

InnerException {"<user xmlns=''> was not expected."} System.Exception {System.InvalidOperationException}

我已经搜索了一些资料,找到的最好解决方案是在序列化内容时向序列化器添加空名称空间,但是我没有序列化它,所以我不能这样做。

我也有一些用于接收状态的代码,它很好用。

所以可以有人解释一下为什么会出现这个错误吗?以及可能的解决方案?


在我的情况下,是因为XmlSerializer的声明有误。所以也要检查一下这个。 - Mangesh
我必须在类中添加一个带有XmlAttribute的字段。请参见链接 - Stefan Varga
12个回答

335

你可以使用XmlRoot属性装饰你的根实体,在编译时将被使用。

[XmlRoot(Namespace = "www.contoso.com", ElementName = "MyGroupName", DataType = "string", IsNullable=true)]

或者在运行时反序列化时指定根属性。

XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "user";
// xRoot.Namespace = "http://www.cpandl.com";
xRoot.IsNullable = true;

XmlSerializer xs = new XmlSerializer(typeof(User),xRoot);

6
你可以为该类添加一个XmlRoot属性。 http://msdn.microsoft.com/en-us/library/83y7df3e(VS.71).aspx[XmlRoot(Namespace = "www.contoso.com", ElementName = "MyGroupName", DataType = "string", IsNullable=true)] - david valentine
50
XML是大小写敏感的。"User"和"user"是不同的名称。 - John Saunders
4
我给出了负评,因为我认为XmlRoot信息应该在类本身中定义,而不是在反序列化的位置定义。因此,我认为Junto的解决方案更好。 - GuiSim
6
你假设 OP 对原实体具有控制权,但两种答案都是有效的。在我的情况下,我无法将 XmlRoot 添加到实体中,因为它作为 MessageContract 的一部分使用。使用上述方法适用于我的场景。 - Bronumski
5
@GuiSim,我不反对原帖所说的。我完全掌控我的根实体,但无法使用rootattribute,因为它会与MessageContract attribute产生冲突。两个答案都是有效的,在评论中还提出了另一种选择。重点是你正在对一个有效的答案进行负面评价,而不是错误的答案。如果您不认为它是最好的选择,那就不要投票即可。 - Bronumski
显示剩余8条评论

156

更简单的方法是在类顶部添加以下注解:

[Serializable, XmlRoot("user")]
public partial class User
{
}

简单明了 - mayowa ogundele
啊!你刚刚帮我省去了将 XML 转换为类对象的 6 次手动转换!它的效果和预期一样。谢谢! - Thameem

33
XmlSerializer xs = new XmlSerializer(typeof(User), new XmlRootAttribute("yourRootName")); 

3
这非常适用于那些否则需要依靠条件语句来设置属性的情况。 - Den
2
非常简单,完全解决了我的问题。谢谢! - A.W

16
错误信息太模糊了,对我来说,我有这个代码:
var streamReader = new StreamReader(response.GetResponseStream());
var xmlSerializer = new XmlSerializer(typeof(aResponse));
theResponse = (bResponse) xmlSerializer.Deserialize(streamReader);

注意,我在实例化xmlSerializer时使用了aResponse,但在反序列化时不小心将其强制转换为了bResponse。

2
刚遇到了一个类似的问题。xmlserializer被初始化为typeof(T),而我正在将其转换为List<T>。 - nurettin
1
我在父类ClassA的子类ClassB上声明了XmlRoot(..)。我使用了new XmlSerializer(typeof(ClassA))而不是在ClassB上使用,并将对象强制转换为它。感谢您指出! - Shishir Gupta

8

最简单和最好的解决方案就是在你想要反序列化的类中使用XMLRoot属性。

例如:

[XmlRoot(ElementName = "YourPreferableNameHere")]
public class MyClass{
...
}

另外,使用以下的汇编语言

using System.Xml.Serialization;

8
有人能给出一个解释吗?为什么需要使用XmlRoot()属性来解决这个问题?这里有5个答案只是说“只需添加此代码”,没有任何解释。人们七年后仍在回答,仍然只是“添加此 XmlRoot 代码”。我选择了最新的答案来请求解释。 - Quantic
谢谢 @Quantic,XmlRoot 允许您创建一个新的 XML 值,而不是使用默认根元素,您可以自定义它。这只是一种在编译时添加到 XML 中的装饰,将消除某些兼容性问题。希望你明白我的意思。 - Khawaja Asim

7
在我的情况下,我的XML文件有多个命名空间和属性。因此我使用了这个网站生成对象 - https://xmltocsharp.azurewebsites.net/
然后使用以下代码进行反序列化:
 XmlDocument doc =  new XmlDocument();
        doc.Load("PathTo.xml");
        User obj;
        using (TextReader textReader = new StringReader(doc.OuterXml))
        {
            using (XmlTextReader reader = new XmlTextReader(textReader))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(User));
                obj = (User)serializer.Deserialize(reader);
            }
        }

3
提供的链接对将XML反序列化为类提供了巨大的帮助。 - smr5
提供的URL对我来说也太长了。 - thargenediad

6

正如John Saunders所说,检查类/属性名称是否与XML的大写匹配。如果不是这种情况,则问题也会发生。


3
在我的情况下,唯一有效的方法是使用David Valentine的代码。在Person类中使用Root Attr.没有帮助。
我有这个简单的XML:
<?xml version="1.0"?>
<personList>
 <Person>
  <FirstName>AAAA</FirstName>
  <LastName>BBB</LastName>
 </Person>
 <Person>
  <FirstName>CCC</FirstName>
  <LastName>DDD</LastName>
 </Person>
</personList>

C#类:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

从主方法反序列化C#代码:

XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "personList";
xRoot.IsNullable = true;
using (StreamReader reader = new StreamReader(xmlFilePath))
{
List<Person> result = (List<Person>)(new XmlSerializer(typeof(List<Person>), xRoot)).Deserialize(reader);
 int numOfPersons = result.Count;
}  

这个对我起作用了,但是在这个例子中,我必须使用相同的大小写名称“Person”作为类名。 - tedi
或者您可以在您的项类上方使用[XmlType(TypeName = "Person")]注释。 - tedi

3

我遇到的问题是根元素实际上有一个xmlns="abc123"。

所以必须使用XmlRoot("elementname",NameSpace="abc123")。


绝对有帮助……如果您的XML中有命名空间,您必须添加该命名空间。 - rios0rios0

3

除了以下方法,对于这些错误信息,没有什么能够解决我的问题

... was not expected, 
... there is an error in XML document (1,2)
... System.FormatException Input String was not in correct format ...

除此之外的方法

1- 您需要将要反序列化为对象的xml响应作为字符串进行检查。

2- 使用在线工具进行字符串非转义和xml格式化/美化。

3- 确保您尝试映射/反序列化xml字符串到的C#类(主类) 具有与响应根元素匹配的XmlRootAttribute

例如:

我的XML响应开始是这样的:

<ShipmentCreationResponse xmlns="http://ws.aramex.net/ShippingAPI/v1/">
       <Transaction i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"/>
           ....

而 C#类定义 + 属性如下:

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="ShipmentCreationResponse", WrapperNamespace="http://ws.aramex.net/ShippingAPI/v1/", IsWrapped=true)]
public partial class ShipmentCreationResponse {
  .........
}

请注意,该类定义中没有 "XmlRootAttribute" 标记。
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://ws.aramex.net/ShippingAPI/v1/", IsNullable = false)]

当我尝试使用通用方法进行反序列化时:

public static T Deserialize<T>(string input) where T : class
{
    System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(T));

    using (System.IO.StringReader sr = new System.IO.StringReader(input))
    {
        return (T)ser.Deserialize(sr);
    }
}





var _Response = GeneralHelper.XMLSerializer.Deserialize<ASRv2.ShipmentCreationResponse>(xml);

我之前遇到了上述错误。

... was not expected, ... there is an error in XML document (1,2) ...

现在只需添加“XmlRootAttribute”,就可以永久修复这个问题以及我遇到类似问题的每一个请求/响应。
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://ws.aramex.net/ShippingAPI/v1/", IsNullable = false)]

..

[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://ws.aramex.net/ShippingAPI/v1/")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://ws.aramex.net/ShippingAPI/v1/", IsNullable = false)]
public partial class ShipmentCreationResponse
{
    ........
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接