{"<user xmlns = ''> nie było oczekiwane.} Deserializowanie XML-a na Twitterze

211

Wciągam XML z Twittera przez OAuth.

Przesyłam żądanie do http://twitter.com/account/verify_credentials.xml , które zwraca następujący kod 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>

Korzystam z następującego kodu do deserializacji:

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

I mam następujące dla mojej Userklasy:

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

}

Ale gdy deserializuje powyższy kod XML, aplikacja rzuca:

  • $ wyjątek {„Wystąpił błąd w dokumencie XML (2, 2)."} System.Exception {System.InvalidOperationException}

  • InnerException {"<user xmlns = ''> nie był oczekiwany."} System.Exception {System.InvalidOperationException}

Teraz szukałem i najlepszym rozwiązaniem, jakie mogę znaleźć, jest dodanie pustych przestrzeni nazw do serializatora podczas serializacji treści, ale nie serializuję tego, więc nie mogę.

Mam również kod do odbierania statusów, co działa dobrze.

Czy ktoś może mi wyjaśnić, dlaczego występuje błąd? Jak również możliwe rozwiązanie?

Z góry dziękuję.

Lloydsparkes
źródło
W moim przypadku było to spowodowane błędną deklaracją XmlSerializer. Sprawdź to także.
Mangesh
Musiałem dodać pole z XmlAttribute do klasy. Zobacz link
Stefan Varga,

Odpowiedzi:

263

Albo udekoruj swoją jednostkę główną atrybutem XmlRoot, który będzie używany podczas kompilacji.

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

Lub określ atrybut root podczas serializacji w czasie wykonywania.

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

XmlSerializer xs = new XmlSerializer(typeof(User),xRoot);
David Valentine
źródło
6
Możesz dodać atrybut XmlRoot do klasy msdn.microsoft.com/en-us/library/83y7df3e(VS.71).aspx [XmlRoot (Namespace = "www.contoso.com", ElementName = "MyGroupName", DataType = „string”, IsNullable = true)]
David Valentine
39
W XML rozróżniana jest wielkość liter. „Użytkownik” i „użytkownik” to różne nazwy.
John Saunders
4
Odrzuciłem głos, ponieważ uważam, że informacje XmlRoot powinny być zdefiniowane w samej klasie, a nie tam, gdzie jest ona przekształcana z postaci szeregowej. Z tego powodu rozwiązanie Junto jest, moim zdaniem, lepsze.
GuiSim
4
@GuiSim Zakładasz, że OP ma kontrolę nad oryginalnym bytem. Obie odpowiedzi są prawidłowe. W moim przypadku nie mogę dodać XmlRoot do encji, ponieważ jest ona używana jako część MessageContract. Zastosowanie powyższej metody działa w moim scenariuszu.
Bronumski
4
@GuiSim Nie zgadzam się z tym, co powiedział PO. Mam pełną kontrolę nad moją jednostką główną, ale nie mogę użyć atrybutu root, ponieważ powoduje on konflikt z atrybutem MessageContract. Obie odpowiedzi są prawidłowe, a alternatywa została przedstawiona w komentarzach. Chodzi o to, że głosujesz w dół poprawną, a nie złą odpowiedź. Jeśli nie zgadzasz się, że to najlepsze, po prostu nie głosuj.
Bronumski
135

Jeszcze łatwiej jest po prostu dodać następujące adnotacje na szczycie klasy:

[Serializable, XmlRoot("user")]
public partial class User
{
}
Rebecca
źródło
Prosty i prosty
mayowa ogundele
25
XmlSerializer xs = new XmlSerializer(typeof(User), new XmlRootAttribute("yourRootName")); 
Ranadheer Reddy
źródło
2
Jest to fantastyczne w przypadkach, w których w przeciwnym razie trzeba polegać na warunkach dla atrybutów.
Den Delimarsky
2
Bardzo prosty i całkowicie naprawił moją skrzynkę. Dzięki!
AW
12

Komunikat o błędzie jest tak niejasny, że dla mnie miałem ten kod:

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

Zauważ, że xmlSerializer jest tworzony przy pomocy aResponse, ale po deserializacji przypadkowo rzuciłem go na bResonse.

Jeremy Thompson
źródło
2
Właśnie miałem podobny problem. xmlserializer został zainicjowany na typeof (T), a ja przesyłałem na List <T>
nurettin
1
Zadeklarowałem XmlRoot(..)w klasie dziecięcej klasy ClassBrodzicielskiej ClassA. Użyłem new XmlSerializer(typeof(ClassA)zamiast niego ClassBi rzuciłem na niego przedmiot. Dzięki za wskazanie!
Shishir Gupta,
6

Najprostszym i najlepszym rozwiązaniem jest użycie atrybutu XMLRoot w swojej klasie, w którym chcesz dokonać deserializacji.

Lubić:

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

Użyj także następującego zestawu :

using System.Xml.Serialization;
Khawaja Asim
źródło
3
Czy ktoś chce wyjaśnić? DlaczegoXmlRoot() atrybut jest potrzebny do rozwiązania tego problemu? Jest tutaj 5 odpowiedzi, które mówią „po prostu dodaj ten kod”, a nie jedno wyjaśnienie. Ludzie odpowiadają 7 lat później i nadal jest to tylko „Dodaj ten kod XmlRoot”. Ze wszystkich odpowiedzi wybrałem najnowszą z prośbą o wyjaśnienie.
Quantic
Dziękuję @Quantic, XmlRoot pozwala na utworzenie nowej wartości xml zamiast używania domyślnego katalogu głównego, który możesz dostosować. To tylko rodzaj dekoracji, którą dodasz do swojego pliku xml podczas kompilacji. Wyeliminuje czasami problemy ze zgodnością. Mam nadzieję, że rozumiesz.
Khawaja Asim
5

Jak mówi John Saunders, sprawdź, czy nazwy klas / właściwości pasują do wielkiej obudowy XML. Jeśli tak nie jest, problem również wystąpi.

Luuk
źródło
2

Mój problem polegał na tym, że jeden z moich elementów miał atrybut xmlns:

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

Bez względu na to, co próbowałem, atrybut xmlns wydawał się zrywać z serializatorem, więc usunąłem wszelkie ślady xmlns = "..." z pliku xml:

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

i voila! Wszystko działało

Teraz analizuję plik xml, aby usunąć ten atrybut przed deserializacją. Nie jestem pewien, dlaczego to działa, może moja sprawa jest inna, ponieważ element zawierający atrybut xmlns nie jest elementem głównym.

Patrick Borkowicz
źródło
W twoim pliku określono, że RETS-RESPONSE znajduje się w przestrzeni nazw „blahblah”. Gdyby to nie pasowało do twojego schematu, element nie zostałby znaleziony. Dodanie domyślnej przestrzeni nazw powoduje również wiele innych problemów z odwołaniami.
Suncat2000
2

Jedyną rzeczą, która działała w moim przypadku, było użycie Davida Valentine Code. Korzystanie z Root Attr. w klasie Osoba nie pomogło.

Mam ten prosty plik XML:

<?xml version="1.0"?>
<personList>
 <Person>
  <FirstName>AAAA</FirstName>
  <LastName>BBB</LastName>
 </Person>
 <Person>
  <FirstName>CCC</FirstName>
  <LastName>DDD</LastName>
 </Person>
</personList>

Klasa C #:

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

Kod C # deserializacji z głównej metody:

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;
}  
użytkownik2596085
źródło
2

W moim przypadku mój xml miał wiele przestrzeni nazw i atrybutów. Więc użyłem tej strony do wygenerowania obiektów - https://xmltocsharp.azurewebsites.net/

I użyłem poniższego kodu do deserializacji

 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);
            }
        }
JoR
źródło
Link zapewnił ogromną pomoc w deserializacji xml do klasy.
smr5
1

Mój problem polegał na tym, że element główny faktycznie ma xmlns = "abc123"

Więc musiałem zrobić XmlRoot („nazwa elementu”, NameSpace = „abc123”)

Nacięcie
źródło
1

Wszystkie powyższe nie działały dla mnie, ale było to: Sprawdź, czy nazwa elementu root klasy jest dokładnie taka sama jak nazwa z rozróżnianiem wielkości liter w XML .

shdr
źródło
1

Nic nie działało dla mnie z tymi błędami Z WYJĄTKIEM

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

Z wyjątkiem tej drogi

1- Musisz sprawdzić odpowiedź xml jako ciąg znaków (odpowiedź, którą próbujesz zdistrializować do obiektu)

2- Użyj narzędzi online do unescape ciągów i prettify / formatter xml

3 - UPEWNIJ SIĘ, że klasa C # (klasa główna), którą próbujesz zmapować / deserializować ciąg xml, ma HAS AN XmlRootAttribute pasujący do elementu głównego odpowiedzi.

Przykład:

Moja odpowiedź XML wyglądała tak:

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

Definicja + atrybuty klasy C # wyglądały następująco:

[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 {
  .........
}

Zauważ, że definicja klasy nie ma „ XmlRootAttribute

[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://ws.aramex.net/ShippingAPI/v1/", IsNullable = false)]

A kiedy próbuję dokonać serializacji przy użyciu ogólnej metody:

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

Otrzymałem powyższe błędy

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

Teraz, po prostu dodając „XmlRootAttribute”, który naprawił problem na zawsze, i dla wszystkich innych żądań / odpowiedzi miałem podobny problem z:

[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
{
    ........
}
Adel Mourad
źródło