{"<user xmlns = ''> не очікувалося.} Десеріалізація Twitter XML


211

Я перетягую 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, додаток кидає наступне:

  • $ виключення {"У документі XML (2, 2) є помилка."} System.Exception {System.InvalidOperationException}

  • InnerException {"<user xmlns = ''> не очікувалося."} ​​System.Exception {System.InvalidOperationException}

Зараз я провів пошук, і найкраще рішення, яке я можу знайти, - це додавати порожні простори імен до серіалізатора, коли ви серіалізуєте вміст, але я не серіалізую його, тому я не можу.

У мене також є якийсь код прийому Статусів, який прекрасно працює.

То чи може хтось мені пояснити, чому трапляється помилка? Як і можливе рішення?

Заздалегідь спасибі.


У моєму випадку це було через неправильне оголошення XmlSerializer. Тож перевірте і це.
Мангеш

Мені довелося додати поле з XmlAttribute в клас. Дивіться посилання
Стефан Варга

Відповіді:


263

Або прикрасьте свою кореневу сутність атрибутом XmlRoot, який буде використаний під час компіляції.

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

Або вказати атрибут root під час de serialization під час виконання.

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 = "рядок", IsNullable = правда)]
David

39
XML відрізняється від регістру. "Користувач" і "користувач" - це різні назви.
Джон Сондерс

4
Я поступив на користь, тому що я вважаю, що інформацію XmlRoot слід визначати на самому класі, а не там, де вона десеріалізується. З цього приводу рішення Юнто, на мій погляд, є вищим.
GuiSim

4
@GuiSim Ви припускаєте, що ОП має контроль над початковою сутністю. Обидві відповіді справедливі. У моєму випадку я не можу додати XmlRoot до об'єкта, оскільки він використовується як частина MessageContract. Використання вищевказаного методу працює для мого сценарію.
Бронумський

4
@GuiSim Я не згоден з тим, що сказав ОП. Я повністю контролюю свою кореневу сутність, але не можу використовувати rootattribute, оскільки це суперечить атрибуту MessageContract. Обидві відповіді справедливі, і альтернатива була представлена ​​в коментарях. Справа в тому, що ви вниз голосуєте за правильну відповідь, а не про неправильну відповідь. Якщо ви не згодні, що це найкраще, просто не голосуйте.
Бронумський

135

Ще простіше просто додати наступні примітки до вершини свого класу:

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

Просте і прямолінійне
mayowa ogundele

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)замість цього, ClassBа також кидав на нього об'єкт. Дякуємо, що вказали!
Шишир Гупта

6

Найпростіше і найкраще рішення - просто використовувати атрибут XMLRoot у своєму класі, в якому ви хочете десаріалізувати.

Подібно до:

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

Також використовуйте таку збірку :

using System.Xml.Serialization;

3
Хтось хоче дати пояснення? Чому це XmlRoot()атрибут необхідно , щоб усунути цю проблему? Тут є 5 відповідей, які говорять: "просто додайте цей код", а не одне пояснення. Люди відповідають 7 років потому, і все ще просто "Додати цей XmlRoot код". З усіх відповідей я вибрав найновішу, щоб попросити пояснення.
Quantic

Завдяки @Quantic, XmlRoot дозволяють вам створити нове значення xml, а не використовувати root за замовчуванням, ви можете налаштувати це. Це просто вид прикраси, яку ви додасте до свого XML під час компіляції. Деякі проблеми усунуть сумісність. Сподіваюся, ви зрозуміли мою думку.
Khawaja Asim

5

Як каже Джон Сондерс, перевірте, чи відповідають назви класів / властивостей основним колонком вашого XML. Якщо це не так, проблема також виникне.


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

Єдине, що спрацювало в моєму випадку - це використання кодексу валентного валентіна. Використання кореня 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 # від основного методу:

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

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 ("ім'я елемента", NameSpace = "abc123")


1

Все вище для мене не працювало, але це було так: Перевірте, чи ім'я елемента Root класу точно схоже на те, що з регістру XML .


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 на HAS AN 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
{
    ........
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.