{"<user xmlns = ''> wurde nicht erwartet.} Deserialisierung von Twitter XML


211

Ich ziehe das XML von Twitter über OAuth ein.

Ich sende eine Anfrage an http://twitter.com/account/verify_credentials.xml , die das folgende XML zurückgibt:

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

Ich verwende den folgenden Code zum Deserialisieren:

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

Und ich habe folgendes für meine UserKlasse:

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

}

Wenn das obige XML deserialisiert wird, löst die Anwendung Folgendes aus:

  • $ exception {"Im XML-Dokument (2, 2) ist ein Fehler aufgetreten."} System.Exception {System.InvalidOperationException}

  • InnerException {"<user xmlns = ''> wurde nicht erwartet."} System.Exception {System.InvalidOperationException}

Jetzt habe ich mich umgesehen und die beste Lösung, die ich finden kann, besteht darin, dem Serializer leere Namespaces hinzuzufügen, wenn Sie den Inhalt serialisieren, aber ich serialisiere ihn nicht, also kann ich nicht.

Ich habe auch einen Code zum Empfangen von Status, der gut funktioniert.

Kann mir jemand erklären, warum der Fehler auftritt? Sowie eine mögliche Lösung?

Danke im Voraus.


In meinem Fall lag es an einer falschen Erklärung von XmlSerializer. Überprüfen Sie das auch.
Mangesh

Ich musste der Klasse ein Feld mit XmlAttribute hinzufügen . Siehe Link
Stefan Varga

Antworten:


261

Dekorieren Sie entweder Ihre Stammentität mit dem XmlRoot-Attribut, das zur Kompilierungszeit verwendet wird.

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

Oder geben Sie das Root-Attribut an, wenn Sie zur Laufzeit de serialisieren.

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

XmlSerializer xs = new XmlSerializer(typeof(User),xRoot);

6
Sie können der Klasse msdn.microsoft.com/en-us/library/83y7df3e(VS.71).aspx [XmlRoot (Namespace = "www.contoso.com", ElementName = "MyGroupName", DataType = ein XmlRoot-Attribut hinzufügen "string", IsNullable = true)]
David Valentine

39
Bei XML wird zwischen Groß- und Kleinschreibung unterschieden. "Benutzer" und "Benutzer" sind unterschiedliche Namen.
John Saunders

4
Ich habe abgestimmt, weil ich der Meinung bin, dass die XmlRoot-Informationen in der Klasse selbst definiert werden sollten, nicht dort, wo sie deserialisiert werden. Aus diesem Grund ist Juntos Lösung meiner Meinung nach überlegen.
GuiSim

4
@GuiSim Sie gehen davon aus, dass das OP die Kontrolle über die ursprüngliche Entität hat. Beide Antworten sind gültig. In meinem Fall kann ich der Entität kein XmlRoot hinzufügen, da es als Teil eines MessageContract verwendet wird. Die Verwendung der obigen Methode funktioniert für mein Szenario.
Bronumski

4
@GuiSim Ich bin nicht anderer Meinung als das, was das OP gesagt hat. Ich habe die vollständige Kontrolle über meine Stammentität, kann das Stammattribut jedoch nicht verwenden, da es mit dem MessageContract-Attribut in Konflikt steht. Beide Antworten sind gültig und die Alternative wurde in den Kommentaren vorgestellt. Der Punkt ist, dass Sie eine gültige Antwort nicht falsch abstimmen. Wenn Sie nicht der Meinung sind, dass es das Beste ist, stimmen Sie einfach nicht ab.
Bronumski

135

Noch einfacher ist es, die folgenden Anmerkungen oben in Ihrer Klasse hinzuzufügen:

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

Einfach und unkompliziert
Mayowa Ogundele

25
XmlSerializer xs = new XmlSerializer(typeof(User), new XmlRootAttribute("yourRootName")); 

2
Dies ist fantastisch für Fälle, in denen Sie sich ansonsten auf Bedingungen für Attribute verlassen müssten.
Den Delimarsky

2
Sehr einfach und mein Fall komplett behoben. Vielen Dank!
AW

12

Die Fehlermeldung ist so vage, für mich hatte ich diesen Code:

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

Beachten Sie, dass xmlSerializer mit aResponse instanziiert wird, aber beim Deserialisieren habe ich es versehentlich in bResonse umgewandelt.


2
Hatte gerade ein ähnliches Problem. xmlserializer wurde auf typeof (T) initialisiert und ich war
nurettin

1
Ich erklärte XmlRoot(..)auf Kinderklasse ClassBder Elternklasse ClassA. Ich habe new XmlSerializer(typeof(ClassA)statt auf verwendet ClassBund auch Objekt darauf gegossen. Vielen Dank für den Hinweis!
Shishir Gupta

6

Die einfachste und beste Lösung besteht darin, das XMLRoot- Attribut in Ihrer Klasse zu verwenden, in der Sie deserialisieren möchten.

Mögen:

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

Verwenden Sie auch die folgende Baugruppe :

using System.Xml.Serialization;

3
Möchte jemand eine Erklärung geben? Warum wird ein XmlRoot()Attribut benötigt, um dieses Problem zu beheben? Hier gibt es 5 Antworten mit der Aufschrift "Fügen Sie einfach diesen Code hinzu" und keine einzige Erklärung. Die Leute antworten 7 Jahre später und es ist immer noch nur "Diesen XmlRoot-Code hinzufügen". Von allen Antworten habe ich die neueste ausgewählt, um nach einer Erklärung zu fragen.
Quantic

Dank @Quantic können Sie mit XmlRoot einen neuen XML-Wert erstellen, anstatt das Standardstammverzeichnis zu verwenden, das Sie anpassen können. Es ist nur eine Art Dekoration, die Sie beim Kompilieren zu Ihrer XML hinzufügen. Behebt manchmal Kompatibilitätsprobleme. Hoffe du verstehst meinen Standpunkt.
Khawaja Asim

5

Überprüfen Sie, wie John Saunders sagt, ob die Klassen- / Eigenschaftsnamen mit dem Großbuchstaben Ihres XML übereinstimmen. Ist dies nicht der Fall, tritt das Problem ebenfalls auf.


2

Mein Problem war, dass eines meiner Elemente das Attribut xmlns hatte:

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

Unabhängig davon, was ich ausprobiert habe, schien das xmlns-Attribut den Serializer zu beschädigen, daher habe ich alle Spuren von xmlns = "..." aus der xml-Datei entfernt:

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

und voila! Alles hat funktioniert.

Ich analysiere jetzt die XML-Datei, um dieses Attribut vor dem Deserialisieren zu entfernen. Ich bin mir nicht sicher, warum dies funktioniert. Vielleicht ist mein Fall anders, da das Element, das das xmlns-Attribut enthält, nicht das Stammelement ist.


In Ihrer Datei wurde angegeben, dass sich RETS-RESPONSE im Namespace "blahblah" befindet. Wenn das nicht zu Ihrem Schema passt, wurde das Element nicht gefunden. Das Hinzufügen eines Standard-Namespace verursacht auch alle möglichen anderen Referenzprobleme.
Suncat2000

2

Das einzige, was in meinem Fall funktionierte, war die Verwendung von David Valentine Code. Verwenden von Root Attr. in der Person Klasse hat nicht geholfen.

Ich habe diese einfache XML:

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

C # -Klasse:

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

De-Serialization C # -Code von einer Hauptmethode:

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

In meinem Fall hatte meine XML mehrere Namespaces und Attribute. Also habe ich diese Seite benutzt, um die Objekte zu generieren - https://xmltocsharp.azurewebsites.net/

Und den folgenden Code zum Deserialisieren verwendet

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

Der Link bot eine große Hilfe beim Deserialisieren von XML für die Klasse.
smr5

1

Mein Problem war, dass das Stammelement tatsächlich ein xmlns = "abc123" hat.

Musste also XmlRoot machen ("elementname", NameSpace = "abc123")


1

Alles oben hat bei mir nicht funktioniert, aber dies war: Überprüfen Sie, ob der Name des Root-Elements der Klasse genau dem von XML entspricht, wobei zwischen Groß- und Kleinschreibung unterschieden wird .


1

Für diese Fehler hat bei mir nichts funktioniert , AUSSER

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

Außer auf diese Weise

1- Sie müssen die XML-Antwort als Zeichenfolge überprüfen (die Antwort, die Sie versuchen, für ein Objekt zu de-serialisieren).

2- Verwenden Sie Online-Tools für String Unescape und XML Prettify / Formatierer

3- Stellen Sie sicher, dass die C # -Klasse (Hauptklasse), die Sie der XML-Zeichenfolge zuordnen / deserialisieren möchten, ein XmlRootAttribute hat , ein , das dem der Antwort entspricht.

Beispiel:

Meine XML-Antwort sah wie folgt aus:

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

Und die C + -Klassendefinition + Attribute waren wie folgt:

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

Beachten Sie, dass die Klassendefinition nicht " XmlRootAttribute " enthält.

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

Und wenn ich versuche, mit einer generischen Methode zu de serialisieren:

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

Ich habe die obigen Fehler erhalten

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

Durch einfaches Hinzufügen des "XmlRootAttribute", das das Problem für immer und für alle anderen Anfragen / Antworten behoben hat, hatte ich ein ähnliches Problem mit:

[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
{
    ........
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.