{"<пользователь xmlns = ''> не ожидался.} Десериализация Twitter XML

213

Я извлекаю XML из Twitter через OAuth.

Я делаю запрос к 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 = ''> не ожидалось."} System.Exception {System.InvalidOperationException}

Теперь я искал вокруг, и лучшее решение, которое я могу найти, это добавить пустые пространства имен в сериализатор, когда вы сериализуете контент, но я не сериализую его, поэтому я не могу.

У меня также есть код для получения статусов, который отлично работает.

Так может кто-нибудь объяснить мне, почему происходит ошибка? Как и возможное решение?

Заранее спасибо.

lloydsparkes
источник
В моем случае это было из-за неправильного объявления XmlSerializer. Так что проверьте это тоже.
Mangesh
Мне пришлось добавить поле с XmlAttribute в класс. Смотрите ссылку
Стефан Варга

Ответы:

264

Либо украсьте вашу корневую сущность атрибутом 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 в класс msdn.microsoft.com/en-us/library/83y7df3e(VS.71).aspx [XmlRoot (Namespace = "www.contoso.com", ElementName = "MyGroupName", DataType = "string", IsNullable = true)]
Дэвид Валентин
39
XML чувствителен к регистру. «Пользователь» и «пользователь» - это разные имена.
Джон Сондерс
4
Я понизил голосование, потому что чувствую, что информация XmlRoot должна быть определена в самом классе, а не там, где он десериализован. По этой причине решение Junto, на мой взгляд, является лучшим.
GuiSim
4
@GuiSim Вы предполагаете, что OP имеет контроль над исходной сущностью. Оба ответа действительны. В моем случае я не могу добавить XmlRoot к сущности, поскольку он используется как часть MessageContract. Использование вышеуказанного метода работает для моего сценария.
Бронумски
4
@GuiSim Я не согласен с тем, что сказал ОП. У меня есть полный контроль над моей корневой сущностью, но я не могу использовать rootattribute, потому что он конфликтует с атрибутом MessageContract. Оба ответа действительны, и альтернатива была представлена ​​в комментариях. Дело в том, что вы голосуете за правильный ответ, а не за неправильный. Если вы не согласны с тем, что это лучшее, просто не голосуйте.
Бронумски
135

Еще проще просто добавить следующие аннотации в начало вашего класса:

[Serializable, XmlRoot("user")]
public partial class User
{
}
Ребекка
источник
Просто и
понятно
25
XmlSerializer xs = new XmlSerializer(typeof(User), new XmlRootAttribute("yourRootName")); 
Ранэдир Редди
источник
2
Это отлично подходит для случаев, когда в противном случае вам придется полагаться на условные выражения для атрибутов.
Ден Делимарский,
2
Очень просто и исправил мой случай полностью. Спасибо!
AW
12

Сообщение об ошибке настолько расплывчато, для меня у меня был такой код:

var streamReader = new StreamReader(response.GetResponseStream());
var xmlSerializer = new XmlSerializer(typeof(aResponse));
theResponse = (bResponse) xmlSerializer.Deserialize(streamReader);

Обратите внимание, что xmlSerializer создается с помощью aResponse, но при десериализации я случайно привел его к bResonse.

Джереми Томпсон
источник
2
Просто была похожая проблема. xmlserializer был инициализирован для typeof (T), и я приводил в Список <T>
nurettin
1
Я объявил XmlRoot(..)на дочернем классе ClassBродительского класса ClassA. Я использовал new XmlSerializer(typeof(ClassA)вместо on ClassBи также бросил объект к нему. Спасибо за указание!
Шишир Гупта
6

Самое простое и лучшее решение - просто использовать XMLRoot атрибут в вашем классе, который вы хотите десериализовать.

Подобно:

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

Также используйте следующую сборку :

using System.Xml.Serialization;
Хаваджа Асим
источник
3
Кто-нибудь хочет дать объяснение? Почему это XmlRoot()атрибут необходимо , чтобы устранить эту проблему? Здесь есть 5 ответов «просто добавьте этот код», а не одно объяснение. Люди отвечают 7 лет спустя, и все равно это просто «Добавить этот код XmlRoot». Из всех ответов я выбрал самый новый, чтобы попросить объяснения.
Quantic
Спасибо @Quantic, XmlRoot позволяет вам создавать новое значение XML, а не использовать корневой каталог по умолчанию, вы можете настроить его. Это просто украшение, которое вы добавите в свой xml во время компиляции. Устранит несколько раз проблемы совместимости. Надеюсь, вы поняли мою точку зрения.
Хаваджа Асим
5

Как говорит Джон Сондерс, проверьте, соответствуют ли имена классов / свойств заглавным буквам вашего XML. Если это не так, проблема также возникнет.

Luuk
источник
2

Моя проблема была в том, что один из моих элементов имел атрибут xmlns:

<?xml version="1.0" encoding="utf-8"?>
<RETS ReplyCode="0">
    <RETS-RESPONSE xmlns="blahblah">
        ...
    </RETS-RESPONSE>
</RETS>

Независимо от того, что я пробовал, атрибут xmlns, казалось, нарушал сериализатор, поэтому я удалил любой след xmlns = "..." из файла xml:

<?xml version="1.0" encoding="utf-8"?>
<RETS ReplyCode="0">
    <RETS-RESPONSE>
        ...
    </RETS-RESPONSE>
</RETS>

и вуаля! Все работало

Теперь я анализирую XML-файл, чтобы удалить этот атрибут перед десериализацией. Не уверен, почему это работает, возможно, мой случай другой, так как элемент, содержащий атрибут xmlns, не является корневым элементом.

Патрик Боркович
источник
В вашем файле указано, что RETS-RESPONSE находится в пространстве имен "blahblah". Если это не соответствует вашей схеме, элемент не был бы найден. Кроме того, добавление пространства имен по умолчанию также вызывает множество других проблем со ссылками.
Suncat2000
2

Единственное, что сработало в моем случае - это использование кода Дэвида Валентина. Использование Root Attr. в классе Person не помогло.

У меня есть этот простой 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 # из метода Main:

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;
}  
user2596085
источник
2

В моем случае у моего 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);
            }
        }
Джор
источник
Ссылка предоставила огромную помощь для десериализации XML в класс.
smr5
1

Моя проблема заключалась в том, что корневой элемент на самом деле имеет xmlns = "abc123"

Так что пришлось сделать XmlRoot ("elementname", NameSpace = "abc123")

Ник
источник
1

Все вышеперечисленное не сработало для меня, но это было: Проверьте, что имя элемента Root класса точно такое же, как в XML с учетом регистра .

shdr
источник
1

Ничто не помогло мне за эти ошибки, КРОМЕ

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

Кроме этого пути

1. Вам нужно проверить xml-ответ в виде строки (ответ, который вы пытаетесь десериализовать для объекта)

2- Используйте онлайн-инструменты для строки unescape и XML prettify / formatter

3. УБЕДИТЕСЬ, что класс C # (основной класс), который вы пытаетесь отобразить / десериализовать, для строки xml имеет XmlRootAttribute , соответствующий корневому элементу ответа.

Exmaple:

Мой 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
{
    ........
}
Адель Мурад
источник