{"<user xmlns = ''> n'était pas attendu.} Désérialisation de Twitter XML

213

Je récupère le XML de Twitter via OAuth.

Je fais une demande à http://twitter.com/account/verify_credentials.xml , qui retourne le XML suivant:

<?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>

J'utilise le code suivant pour désérialiser:

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

Et j'ai les éléments suivants pour ma 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; }

}

Mais quand il désérialise le XML ci-dessus, l'application lance ce qui suit:

  • $ exception {"Il y a une erreur dans le document XML (2, 2)."} System.Exception {System.InvalidOperationException}

  • InnerException {"<user xmlns = ''> n'était pas attendue."} System.Exception {System.InvalidOperationException}

Maintenant, j'ai cherché et la meilleure solution que je peux trouver est d'ajouter des espaces de noms vides au sérialiseur lorsque vous sérialisez le contenu, mais je ne le sérialise pas, donc je ne peux pas.

J'ai également un code pour recevoir des statuts, ce qui fonctionne bien.

Alors, quelqu'un peut-il m'expliquer pourquoi l'erreur se produit? Ainsi qu'une solution possible?

Merci d'avance.

lloydsparkes
la source
Dans mon cas, c'était à cause d'une mauvaise déclaration de XmlSerializer. Alors vérifiez cela aussi.
Mangesh
J'ai dû ajouter un champ avec XmlAttribute dans la classe. Voir le lien
Stefan Varga

Réponses:

264

Soit décorez votre entité racine avec l'attribut XmlRoot qui sera utilisé au moment de la compilation.

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

Ou spécifiez l'attribut racine lors de la désérialisation à l'exécution.

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
la source
6
Vous pouvez ajouter un attribut XmlRoot à la 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 est sensible à la casse. "Utilisateur" et "utilisateur" sont des noms différents.
John Saunders
4
J'ai rétrogradé parce que je pense que les informations XmlRoot devraient être définies sur la classe elle-même, pas là où elles sont désérialisées. Pour cette raison, la solution de Junto est, à mon avis, supérieure.
GuiSim
4
@GuiSim Vous supposez que l'OP a le contrôle sur l'entité d'origine. Les deux réponses sont valables. Dans mon cas, je ne peux pas ajouter XmlRoot à l'entité car elle est utilisée dans le cadre d'un MessageContract. L'utilisation de la méthode ci-dessus fonctionne pour mon scénario.
Bronumski
4
@GuiSim Je ne suis pas en désaccord avec ce que le PO a dit. J'ai le contrôle complet de mon entité racine mais je ne peux pas utiliser l'attribut root car il entre en conflit avec l'attribut MessageContract. Les deux réponses sont valables et l'alternative a été présentée dans les commentaires. Le fait est que vous votez contre une réponse valide et non une mauvaise réponse. Si vous n'êtes pas d'accord que c'est le meilleur, ne votez pas.
Bronumski
135

Il est encore plus facile d'ajouter simplement les annotations suivantes en haut de votre classe:

[Serializable, XmlRoot("user")]
public partial class User
{
}
Rebecca
la source
Simple et direct
Mayowa ogundele
25
XmlSerializer xs = new XmlSerializer(typeof(User), new XmlRootAttribute("yourRootName")); 
Ranadheer Reddy
la source
2
C'est fantastique dans les cas où sinon vous devriez vous fier aux conditions pour les attributs.
Den Delimarsky du
2
Très simple et fixe mon cas complètement. Merci!
AW
12

Le message d'erreur est tellement vague, pour moi j'avais ce code:

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

Remarquez que xmlSerializer est instancié avec aResponse mais lors de la désérialisation, je l'ai accidentellement casté en bResonse.

Jeremy Thompson
la source
2
Je viens d'avoir un problème similaire. xmlserializer a été initialisé à typeof (T) et je castais sur List <T>
nurettin
1
J'ai déclaré XmlRoot(..)sur la classe enfant ClassBde la classe parent ClassA. J'ai utilisé new XmlSerializer(typeof(ClassA)au lieu d' ClassBactiver et également coulé un objet dessus. Merci d'avoir souligné!
Shishir Gupta
6

La solution la plus simple et la meilleure consiste simplement à utiliser l' attribut XMLRoot dans votre classe, dans laquelle vous souhaitez désérialiser.

Comme:

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

Utilisez également l' assemblage suivant :

using System.Xml.Serialization;
Khawaja Asim
la source
3
Quelqu'un veut-il donner une explication? Pourquoi unXmlRoot() attribut est-il nécessaire pour résoudre ce problème? Il y a 5 réponses ici qui disent, "ajoutez simplement ce code" et pas une explication. Les gens répondent 7 ans plus tard et c'est toujours juste, "Ajoutez ce code XmlRoot". De toutes les réponses, j'ai choisi la plus récente pour demander une explication.
Quantic
Merci @Quantic, XmlRoot vous permet de créer une nouvelle valeur xml plutôt que d'utiliser la racine par défaut que vous pouvez personnaliser. C'est juste une sorte de décoration que vous ajouterez à votre xml au moment de la compilation. Élimine parfois les problèmes de compatibilité. J'espère que vous comprendrez mon point.
Khawaja Asim
5

Comme le dit John Saunders, vérifiez si les noms de classe / propriété correspondent à la casse majuscule de votre XML. Si ce n'est pas le cas, le problème se produira également.

Luuk
la source
2

Mon problème était qu'un de mes éléments avait l'attribut xmlns:

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

Peu importe ce que j'ai essayé, l'attribut xmlns semblait rompre le sérialiseur, j'ai donc supprimé toute trace de xmlns = "..." du fichier xml:

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

et le tour est joué! Tout fonctionnait.

J'analyse maintenant le fichier xml pour supprimer cet attribut avant de désérialiser. Je ne sais pas pourquoi cela fonctionne, peut-être que mon cas est différent puisque l'élément contenant l'attribut xmlns n'est pas l'élément racine.

Patrick Borkowicz
la source
Votre fichier a spécifié que RETS-RESPONSE se trouvait dans l'espace de noms "blahblah". Si cela ne correspondait pas à votre schéma, l'élément n'aurait pas été trouvé. En outre, l'ajout d'un espace de noms par défaut provoque également toutes sortes d'autres problèmes de référence.
Suncat2000
2

La seule chose qui a fonctionné dans mon cas a été d'utiliser le code david valentine. Utilisation de Root Attr. dans la classe Personne n'a pas aidé.

J'ai ce simple Xml:

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

Code C # de désérialisation d'une méthode principale:

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
la source
2

Dans mon cas, mon xml avait plusieurs espaces de noms et attributs. J'ai donc utilisé ce site pour générer les objets - https://xmltocsharp.azurewebsites.net/

Et utilisé le code ci-dessous pour désérialiser

 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
la source
Le lien a énormément aidé à désérialiser le xml en classe.
smr5
1

Mon problème était que l'élément racine avait en fait un xmlns = "abc123"

Il a donc fallu faire XmlRoot ("elementname", NameSpace = "abc123")

pseudo
la source
1

Tout ce qui précède n'a pas fonctionné pour moi, mais c'était: Vérifiez que le nom de l'élément racine de la classe est exactement comme celui de XML sensible à la casse .

shdr
la source
1

Rien n'a fonctionné pour moi pour ces erreurs SAUF

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

Sauf de cette façon

1- Vous devez inspecter la réponse xml en tant que chaîne (la réponse que vous essayez de désérialiser en un objet)

2- Utilisez des outils en ligne pour échapper les chaînes et prettify / formatter xml

3- ASSUREZ-VOUS que la classe C # (classe principale) que vous essayez de mapper / désérialiser la chaîne xml a HAS AN XmlRootAttribute qui correspond à l'élément racine de la réponse.

Exmaple:

Ma réponse XML regardait comme:

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

Et la définition de la classe C # + les attributs étaient comme:

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

Notez que la définition de classe n'a pas " XmlRootAttribute "

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

Et quand j'essaye de désérialiser en utilisant une méthode générique:

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

J'obtenais les erreurs ci-dessus

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

Maintenant, en ajoutant simplement le "XmlRootAttribute" qui a résolu le problème pour toujours et pour toutes les autres demandes / réponses, j'ai eu un problème similaire avec:

[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
la source