{"<user xmlns = ''> não era esperado.} Desserializando o XML do Twitter

211

Estou puxando o XML do Twitter via OAuth.

Estou fazendo uma solicitação para http://twitter.com/account/verify_credentials.xml , que retorna o seguinte 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>

Estou usando o seguinte código para desserializar:

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

E eu tenho o seguinte para minha Userclasse:

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

}

Mas quando está desserializando o XML acima, o aplicativo lança o seguinte:

  • $ exception {"Há um erro no documento XML (2, 2)."} System.Exception {System.InvalidOperationException}

  • InnerException {"<user xmlns = ''> não era esperado."} System.Exception {System.InvalidOperationException}

Agora, pesquisei e a melhor solução que posso encontrar é adicionar espaços de nomes em branco ao serializador quando você serializa o conteúdo, mas não o serializo, portanto não posso.

Eu também tenho algum código para receber status, o que funciona bem.

Então, alguém pode me explicar por que o erro está acontecendo? Bem como uma solução possível?

Desde já, obrigado.

lloydsparkes
fonte
No meu caso, foi por causa da declaração errada de XmlSerializer. Então verifique isso também.
Mangesh
Eu tive que adicionar campo com XmlAttribute na classe. Veja o link
Stefan Varga

Respostas:

261

Decore sua entidade raiz com o atributo XmlRoot, que será usado no momento da compilação.

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

Ou especifique o atributo raiz ao serializar em tempo de execução.

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
fonte
6
Você pode adicionar um atributo XmlRoot à classe msdn.microsoft.com/en-us/library/83y7df3e(VS.71).aspx [XmlRoot (Namespace = "www.contoso.com", ElementName = "MyGroupName", DataType = "string", IsNullable = true)]
david valentine
39
XML diferencia maiúsculas de minúsculas. "Usuário" e "usuário" são nomes diferentes.
John Saunders
4
Eu diminuí a votação porque acho que as informações XmlRoot devem ser definidas na própria classe, não onde estão sendo desserializadas. Por esse motivo, a solução da Junto é, na minha opinião, superior.
GuiSim 2/12/12
4
@GuiSim Você está assumindo que o OP tem controle sobre a entidade original. Ambas as respostas são válidas. No meu caso, não posso adicionar XmlRoot à entidade, pois ela é usada como parte de um MessageContract. Usar o método acima funciona para o meu cenário.
Bronumski
4
@GuiSim Não discordo do que o OP disse. Eu tenho controle completo da minha entidade raiz, mas não posso usar o atributo rootat porque está em conflito com o atributo MessageContract. Ambas as respostas são válidas e a alternativa foi apresentada nos comentários. O ponto é que você está votando negativamente em uma resposta válida e não em uma resposta errada. Se você não concorda que é o melhor, simplesmente não vote.
Bronumski
135

Ainda mais fácil é adicionar as seguintes anotações ao topo da sua turma:

[Serializable, XmlRoot("user")]
public partial class User
{
}
Rebecca
fonte
Simples e direto #
mayowa ogundele
25
XmlSerializer xs = new XmlSerializer(typeof(User), new XmlRootAttribute("yourRootName")); 
Ranadheer Reddy
fonte
2
Isso é fantástico para casos em que, caso contrário, você teria que confiar em condicionais para atributos.
Den Delimarsky
2
Muito simples e resolvi meu caso completamente. Obrigado!
AW
12

A mensagem de erro é tão vaga, para mim eu tinha esse código:

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

Observe que o xmlSerializer é instanciado com aResponse, mas ao desserializar, acidentalmente o projetei para bResonse.

Jeremy Thompson
fonte
2
Só tive um problema semelhante. XmlSerializer foi inicializado para typeof (T) e eu estava lançando a List <T>
nurettin
1
Eu declarei XmlRoot(..)na classe filho da classe ClassBpai ClassA. Eu usei em new XmlSerializer(typeof(ClassA)vez de on ClassBe também projetei objeto para ele. Obrigado por apontar!
Shishir Gupta
6

A solução mais simples e melhor é usar o atributo XMLRoot em sua classe, na qual você deseja desserializar.

Gostar:

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

Além disso, use o seguinte assembly :

using System.Xml.Serialization;
Khawaja Asim
fonte
3
Alguém quer dar uma explicação? Por que oXmlRoot() atributo é necessário para corrigir esse problema? Existem 5 respostas aqui que dizem "basta adicionar este código" e nenhuma explicação. As pessoas estão respondendo 7 anos depois e ainda é apenas "Adicione este código XmlRoot". De todas as respostas, escolhi a mais nova para pedir uma explicação.
Quantic
Obrigado @Quantic, XmlRoot permite criar um novo valor xml, em vez de usar a raiz padrão, você pode personalizá-lo. É apenas um tipo de decoração que você adicionará ao seu xml em tempo de compilação. Eliminará algumas vezes problemas de compatibilidade. Espero que você entenda meu ponto de vista.
Khawaja Asim
5

Como diz John Saunders, verifique se os nomes de classe / propriedade correspondem à letra maiúscula do seu XML. Se não for esse o caso, o problema também ocorrerá.

Luuk
fonte
2

Meu problema foi que um dos meus elementos tinha o atributo xmlns:

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

Não importa o que eu tentei, o atributo xmlns parecia estar quebrando o serializador, por isso removi qualquer vestígio de xmlns = "..." do arquivo xml:

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

e pronto! Tudo funcionou.

Agora analiso o arquivo xml para remover esse atributo antes de desserializar. Não sei por que isso funciona, talvez meu caso seja diferente, pois o elemento que contém o atributo xmlns não é o elemento raiz.

Patrick Borkowicz
fonte
Seu arquivo especificou que RETS-RESPONSE estava no espaço para nome "blahblah". Se isso não corresponder ao seu esquema, o elemento não teria sido encontrado. Além disso, adicionar um espaço para nome padrão também causa todos os tipos de outros problemas de referência.
Suncat2000
2

A única coisa que funcionou no meu caso foi usar o código david valentine. Usando atributo raiz. na classe Person não ajudou.

Eu tenho esse XML simples:

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

Classe c #:

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

Des-serialização do código C # de um método 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
fonte
2

No meu caso, meu xml tinha vários namespaces e atributos. Então, eu usei este site para gerar os objetos - https://xmltocsharp.azurewebsites.net/

E usou o código abaixo para desserializar

 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
fonte
O link forneceu uma grande ajuda para desserializar o xml para a classe.
smr5
1

Meu problema foi que o elemento raiz realmente possui um xmlns = "abc123"

Então tive que criar XmlRoot ("elementname", NameSpace = "abc123")

usuario
fonte
1

Tudo acima não funcionou para mim, mas foi o seguinte: Verifique se o nome do elemento Raiz da classe é exatamente igual ao do XML que diferencia maiúsculas de minúsculas .

shdr
fonte
1

Nada funcionou para mim por esses erros, EXCETO

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

Exceto desta maneira

1- Você precisa inspecionar a resposta xml como string (a resposta que você está tentando desserializar para um objeto)

2- Use ferramentas on-line para desescapamento de string e prettify / formatador de xml

3- VERIFIQUE se a classe C # (classe principal) que você está tentando mapear / desserializar a sequência xml para TEM UM XmlRootAttribute que corresponde ao elemento raiz da resposta.

Exemplo:

Minha resposta XML estava olhando como:

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

E a definição de classe C # + atributos era como:

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

Observe que a definição de classe não possui " XmlRootAttribute "

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

E quando tento serializar usando um método genérico:

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

Eu estava recebendo os erros acima

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

Agora, apenas adicionando o "XmlRootAttribute" que corrigia o problema para sempre e para todos os outros pedidos / respostas, tive um problema semelhante com:

[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
fonte