{"<пользователь xmlns = ''> не ожидался.} Десериализация Twitter XML
Так что я извлекаю XML из Twitter через OAuth
Поэтому я делаю запрос к http://twitter.com/account/verify_credentials.xml
Который возвращает следующий 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>» @alexmuller your kidding? it should all be "black tie" dress code</text>
<source><a href="http://code.google.com/p/wittytwitter/" rel="nofollow">Witty</a></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>
Я использую следующий код для десериализации
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);
}
И у меня есть следующее для моего пользовательского класса
[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; }
}
Но при десериализации вышеупомянутого XML я получаю следующую ошибку
$ exception {"Ошибка в XML-документе (2, 2)."} System.Exception {System.InvalidOperationException}
InnerException {"
не ожидалось."} System.Exception {System.InvalidOperationException}
Теперь я искал вокруг, и лучшее решение, которое я могу найти, это добавить пустые пространства имен в сериализатор, когда вы сериализуете контент, НО я не сериализую его, поэтому я не могу.
У меня также есть код для получения статусов, который отлично работает.
Так может кто-нибудь объяснить мне, что и почему происходит ошибка? Как и возможное решение?
заранее спасибо
10 ответов
Либо украсьте вашу корневую сущность атрибутом XmlRoot, который будет использоваться во время компиляции.
[XmlRoot(Namespace = "www.contoso.com", ElementName = "MyGroupName", DataType = "string", IsNullable=true)]
Или укажите корневой атрибут при десериализации во время выполнения.
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "user";
// xRoot.Namespace = "http://www.cpandl.com";
xRoot.IsNullable = true;
XmlSerializer xs = new XmlSerializer(typeof(User),xRoot);
Еще проще просто добавить следующие аннотации в начало вашего класса:
[Serializable, XmlRoot("user")]
public partial class User
{
}
XmlSerializer xs = new XmlSerializer(typeof(User), new XmlRootAttribute("yourRootName"));
Сообщение об ошибке настолько расплывчато, для меня у меня был такой код:
var streamReader = new StreamReader(response.GetResponseStream());
var xmlSerializer = new XmlSerializer(typeof(aResponse));
theResponse = (bResponse) xmlSerializer.Deserialize(streamReader);
Обратите внимание, что xmlSerializer создается с помощью aResponse, но при десериализации я случайно привел его к bResonse.
Самое простое и лучшее решение - просто использовать атрибут XMLRoot в вашем классе, который вы хотите десериализовать.
Подобно:
[XmlRoot(ElementName = "YourPreferableNameHere")]
public class MyClass{
...
}
Также используйте следующую сборку:
using System.Xml.Serialization;
В моем случае у моего xml было несколько пространств имен и атрибутов. Итак, я использовал этот сайт для создания объектов - https://xmltocsharp.azurewebsites.net/
И использовал приведенный ниже код для десериализации
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);
}
}
Как говорит Джон Сондерс, проверьте, соответствуют ли имена классов / свойств заглавным буквам вашего XML. Если это не так, проблема также возникнет.
Единственное, что сработало в моем случае - это использование кода Дэвида Валентина. Использование Root Attr. в классе Person не помогло.
У меня есть этот простой XML:
<?xml version="1.0"?>
<personList>
<Person>
<FirstName>AAAA</FirstName>
<LastName>BBB</LastName>
</Person>
<Person>
<FirstName>CCC</FirstName>
<LastName>DDD</LastName>
</Person>
</personList>
C# класс:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Сериализация кода C# из метода 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;
}
Моя проблема заключалась в том, что корневой элемент на самом деле имеет xmlns="abc123"
Так что пришлось сделать XmlRoot("elementname",NameSpace="abc123")
У меня ничего не работало для этих ошибок, КРОМЕ
... was not expected,
... there is an error in XML document (1,2)
... System.FormatException Input String was not in correct format ...
Кроме этого пути
1- Вам необходимо проверить ответ xml в виде строки (ответ, который вы пытаетесь десериализовать в объект)
2- Используйте онлайн-инструменты для unescape строки и xml prettify / formatter
3- УБЕДИТЕСЬ, что класс C# (основной класс), который вы пытаетесь сопоставить / десериализовать строку xml, ИМЕЕТ атрибут XmlRootAttribute, который соответствует корневому элементу ответа.
Пример:
Мой ответ XML выглядел так:
<ShipmentCreationResponse xmlns="http://ws.aramex.net/ShippingAPI/v1/">
<Transaction i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"/>
....
А определение класса + атрибуты C# было таким:
[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 {
.........
}
Обратите внимание, что определение класса не имеет "XmlRootAttribute"
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://ws.aramex.net/ShippingAPI/v1/", IsNullable = false)]
И когда я пытаюсь де-сериализовать с помощью универсального метода:
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);
Я получал ошибки выше
... was not expected, ... there is an error in XML document (1,2) ...
Теперь, просто добавив "XmlRootAttribute", который навсегда устранил проблему и для всех других запросов / ответов, у меня была аналогичная проблема с:
[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
{
........
}
Все вышеперечисленное не сработало для меня, но это было: Проверьте, что имя элемента Root класса точно такое же, как в XML с учетом регистра.
Моя проблема была в том, что один из моих элементов имел атрибут xmlns:
<?xml version="1.0" encoding="utf-8"?>
<RETS ReplyCode="0">
<RETS-RESPONSE xmlns="blahblah">
...
</RETS-RESPONSE>
</RETS>
Независимо от того, что я пробовал, атрибут xmlns, казалось, нарушал сериализатор, поэтому я удалил любой след xmlns="..." из файла xml:
<?xml version="1.0" encoding="utf-8"?>
<RETS ReplyCode="0">
<RETS-RESPONSE>
...
</RETS-RESPONSE>
</RETS>
и вуаля! Все работало
Теперь я анализирую XML-файл, чтобы удалить этот атрибут перед десериализацией. Не уверен, почему это работает, возможно, мой случай другой, так как элемент, содержащий атрибут xmlns, не является корневым элементом.
Просто добавьте свой корневой элемент в сериализатор. Для вашего XML-документа это user
,
XmlSerializer xs = new XmlSerializer(typeof(User), new XmlRootAttribute("user"));
Мой сценарий состоял в том, что я работал над заданием, в котором код находился в VB.NET, и процедура, которая десериализовала объекты из строк xml, отлично работала для десятков применений, но вчера завершилась неудачно, так как "user xmlns='" не ожидался ошибка (когда в него была брошена строка xml, представляющая собой сериализацию объекта, свойство которого само было сериализованным объектом). Ответы выше помогли мне решить эту проблему, приняв эту работающую подпрограмму...
' DESERIALIZE OBJECT FROM XML STRING
Public Shared Function DeserializeFromXml(Of T)(ByVal xml As String) As T
Dim response As T = Nothing
Try
Using reader As TextReader = New StringReader(xml)
response = DirectCast(New XmlSerializer(GetType(T)).Deserialize(reader), T)
End Using
Catch ex As Exception
End Try
Return response
End Function
... скопируйте этот код и создайте новую подпрограмму, которая позволит вызывающей стороне предоставить строку "Имя корневого атрибута". Новая подпрограмма десериализовала "проблемный" объект из его сериализованной строки XML без ошибок:
' DESERIALIZE OBJECT FROM XML STRING, SUPPLYING A ROOT ATTRIBUTE ELEMENT NAME
Public Shared Function DeserializeFromXmlWithRootAttribute(Of T)(ByVal xml As String, ByVal rootAttributeName As String) As T
Dim response As T = Nothing
Try
Using reader As TextReader = New StringReader(xml)
Dim xra As New XmlRootAttribute()
xra.ElementName = rootAttributeName
xra.IsNullable = True
response = DirectCast(New XmlSerializer(GetType(T), xra).Deserialize(reader), T)
End Using
Catch ex As Exception
End Try
Return response
End Function