{"<user xmlns = ''> tidak diharapkan.} Deserializing Twitter XML

213

Saya menarik XML dari Twitter melalui OAuth.

Saya sedang melakukan permintaan ke http://twitter.com/account/verify_credentials.xml , yang mengembalikan XML berikut:

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

Saya menggunakan kode berikut untuk Deserialize:

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

Dan saya memiliki yang berikut untuk Userkelas saya :

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

}

Tetapi ketika deserializing XML di atas aplikasi melempar hal berikut:

  • $ exception {"Ada kesalahan dalam dokumen XML (2, 2)."} System.Exception {System.InvalidOperationException}

  • InnerException {"<user xmlns = ''> tidak diharapkan."} System.Exception {System.InvalidOperationException}

Sekarang saya telah mencari-cari dan solusi terbaik yang dapat saya temukan adalah menambahkan ruang nama kosong ke serializer ketika Anda membuat serial konten, tapi saya tidak membuat serialisasi jadi saya tidak bisa.

Saya juga punya beberapa kode untuk menerima Status, yang berfungsi dengan baik.

Jadi bisakah seseorang menjelaskan kepada saya mengapa kesalahan itu terjadi? Serta solusi yang mungkin?

Terima kasih sebelumnya.

lloydsparkes
sumber
Dalam kasus saya, itu karena salah deklarasi XmlSerializer. Jadi periksa juga.
Mangesh
Saya harus menambahkan bidang dengan XmlAttribute ke dalam kelas. Lihat tautan
Stefan Varga

Jawaban:

264

Hiasi entitas root Anda dengan atribut XmlRoot yang akan digunakan pada waktu kompilasi.

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

Atau tentukan atribut root saat membuat serial saat runtime.

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
sumber
6
Anda bisa menambahkan atribut XmlRoot ke kelas 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 peka huruf besar-kecil. "Pengguna" dan "pengguna" adalah nama yang berbeda.
John Saunders
4
Saya downvoted karena saya merasa bahwa informasi XmlRoot harus didefinisikan pada kelas itu sendiri, bukan di mana itu deserialized. Untuk alasan ini, solusi Junto, menurut saya, lebih unggul.
GuiSim
4
@ GuiSim Anda mengasumsikan bahwa OP memiliki kendali atas entitas asli. Kedua jawaban itu valid. Dalam kasus saya, saya tidak dapat menambahkan XmlRoot ke entitas karena digunakan sebagai bagian dari MessageContract. Menggunakan metode di atas berfungsi untuk skenario saya.
Bronumski
4
@ GuiSim Saya tidak setuju dengan apa yang dikatakan OP. Saya memiliki kontrol penuh atas entitas root saya tetapi tidak dapat menggunakan rootattribute karena bertentangan dengan atribut MessageContract. Kedua jawaban tersebut valid dan alternatifnya disajikan dalam komentar. Intinya adalah Anda turun memilih jawaban yang valid bukan jawaban yang salah. Jika Anda tidak setuju bahwa itu adalah yang terbaik, jangan memilih.
Bronumski
135

Lebih mudah lagi dengan menambahkan anotasi berikut ke bagian atas kelas Anda:

[Serializable, XmlRoot("user")]
public partial class User
{
}
Rebecca
sumber
Sederhana dan Mudah
mayowa ogundele
25
XmlSerializer xs = new XmlSerializer(typeof(User), new XmlRootAttribute("yourRootName")); 
Ranadheer Reddy
sumber
2
Ini fantastis untuk kasus-kasus di mana kalau tidak Anda harus bergantung pada persyaratan untuk atribut.
Den Delimarsky
2
Sangat sederhana dan memperbaiki kasus saya sepenuhnya. Terima kasih!
AW
12

Pesan kesalahannya sangat samar, bagi saya saya memiliki kode ini:

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

Perhatikan xmlSerializer dipakai dengan Respons aRes tetapi pada deserialisasi saya sengaja melemparkannya ke bResonse.

Jeremy Thompson
sumber
2
Baru saja mengalami masalah serupa. xmlserializer diinisialisasi ke typeof (T) dan saya casting ke Daftar <T>
nurettin
1
Saya mendeklarasikan XmlRoot(..)pada kelas anak ClassBdari kelas induk ClassA. Saya menggunakan new XmlSerializer(typeof(ClassA)bukan pada ClassBdan juga melemparkan benda ke sana. Terima kasih telah menunjukkan!
Shishir Gupta
6

Solusi paling sederhana dan terbaik adalah dengan menggunakan atribut XMLRoot di kelas Anda, di mana Anda ingin deserialize.

Suka:

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

Juga, gunakan Majelis berikut :

using System.Xml.Serialization;
Khawaja Asim
sumber
3
Adakah yang mau memberi penjelasan? Mengapa adalah XmlRoot()atribut yang diperlukan untuk memperbaiki masalah ini? Ada 5 jawaban di sini yang mengatakan, "cukup tambahkan kode ini" dan tidak satu penjelasan. Orang-orang menjawab 7 tahun kemudian dan itu tetap saja, "Tambahkan kode XmlRoot ini". Dari semua jawaban saya memilih yang terbaru untuk meminta penjelasan.
Quantic
Terima kasih @Quantic, XmlRoot memungkinkan Anda membuat nilai xml baru daripada menggunakan root default, Anda dapat menyesuaikannya. Ini hanya jenis hiasan yang akan Anda tambahkan ke xml Anda pada waktu kompilasi. Akan menghilangkan masalah kompatibilitas beberapa kali. Semoga Anda mengerti maksud saya.
Khawaja Asim
5

Seperti yang dikatakan John Saunders, periksa apakah nama kelas / properti cocok dengan huruf kapital dari XML Anda. Jika ini bukan masalahnya, masalahnya juga akan terjadi.

Luuk
sumber
2

Masalah saya adalah salah satu elemen saya memiliki atribut xmlns:

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

Apa pun yang saya coba atribut xmlns tampaknya melanggar serializer, jadi saya menghapus jejak xmlns = "..." dari file xml:

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

dan voila! Semuanya berhasil.

Saya sekarang mem-parsing file xml untuk menghapus atribut ini sebelum deserializing. Tidak yakin mengapa ini berhasil, mungkin kasus saya berbeda karena elemen yang berisi atribut xmlns bukan elemen root.

Patrick Borkowicz
sumber
File Anda menentukan bahwa RETS-RESPONSE berada di namespace "blahblah". Jika itu tidak cocok dengan skema Anda, elemen tersebut tidak akan ditemukan. Juga, menambahkan namespace default juga menyebabkan semua jenis masalah referensi lainnya.
Suncat2000
2

Satu-satunya hal yang berhasil dalam kasus saya adalah dengan menggunakan kode valentine david. Menggunakan Root Attr. di kelas Person tidak membantu.

Saya punya Xml sederhana ini:

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

Kelas C #:

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

De-Serialisasi kode C # dari metode Utama:

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;
}  
pengguna2596085
sumber
2

Dalam kasus saya, xml saya memiliki beberapa ruang nama dan atribut. Jadi saya menggunakan situs ini untuk menghasilkan objek - https://xmltocsharp.azurewebsites.net/

Dan menggunakan kode di bawah ini untuk deserialize

 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
sumber
Tautan menyediakan bantuan besar untuk deserialize xml ke kelas.
smr5
1

Masalah saya adalah bahwa elemen root sebenarnya memiliki xmlns = "abc123"

Jadi harus membuat XmlRoot ("elementname", NameSpace = "abc123")

Nick
sumber
1

Semua di atas tidak bekerja untuk saya, tetapi ini adalah: Periksa bahwa nama elemen Root kelas persis seperti yang dari XML case sensitive .

shdr
sumber
1

Tidak ada yang berfungsi untuk saya untuk kesalahan ini KECUALI

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

Kecuali dengan cara ini

1- Anda perlu memeriksa respons xml sebagai string (respons yang Anda coba untuk der-serialkan ke objek)

2- Gunakan alat online untuk string unescape dan xml prettify / formatter

3- PASTIKAN bahwa C # Class (kelas utama) yang Anda coba petakan / deserialize string xml untuk MEMILIKI XmlRootAttribute yang cocok dengan elemen root dari respons.

Exmaple:

Respons XML saya menatap seperti:

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

Dan atribut definisi # kelas C adalah:

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

Perhatikan bahwa definisi kelas tidak memiliki " XmlRootAttribute "

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

Dan ketika saya mencoba untuk membuat cerita bersambung menggunakan metode generik:

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

Saya mendapatkan kesalahan di atas

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

Sekarang dengan hanya menambahkan "XmlRootAttribute" yang memperbaiki masalah selama-lamanya dan untuk setiap permintaan / tanggapan lainnya saya memiliki masalah serupa dengan:

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