I'm looking for a way with C# which I can deserialize XML below into a class. I can read it with XmlDocument.LoadXml() but I want to deserialize it into the object.
I tried to use XmlSerializer for the object:
[XmlRoot(ElementName = "properties", Namespace = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata") ]
public class MyDto
{
[XmlElement(ElementName = "ObjectID", Namespace = "http://schemas.microsoft.com/ado/2007/08/dataservices")]
public string ObjectID { get; set; }
public string ContactID { get; set; }
}
My Code (memory stream is filled with xml):
var ms = new MemoryStream();
var w = XmlWriter.Create(ms, new XmlWriterSettings
{
Indent = true,
IndentChars = " ",
OmitXmlDeclaration = false,
Encoding = new UTF8Encoding(false),
});
XmlSerializer serializer = new XmlSerializer(typeof(MyDto));
var data = (MyDto)serializer.Deserialize(ms);
but I got the error
System.InvalidOperationException: There is an error in XML document (0, 0). ---> System.Xml.XmlException: Root element is missing.
<?xml version="1.0" encoding="utf-8"?>
<Content type="application/xml">
<m:properties xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<d:ObjectID xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">920D2</d:ObjectID>
<d:ContactID xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">99999</d:ContactID>
</m:properties>
</Content>
Your class object for XmlSerializer quite wrong or not suitable for your XML.
You can get your proper class object for your xml from xmltocsharp
Try below class object.
[XmlRoot("ObjectID", Namespace = "http://schemas.microsoft.com/ado/2007/08/dataservices")]
public class ObjectID
{
[XmlAttribute("d", Namespace = "http://www.w3.org/2000/xmlns/")]
public string D { get; set; }
[XmlText]
public string Text { get; set; }
}
[XmlRoot("ContactID", Namespace = "http://schemas.microsoft.com/ado/2007/08/dataservices")]
public class ContactID
{
[XmlAttribute("d", Namespace = "http://www.w3.org/2000/xmlns/")]
public string D { get; set; }
[XmlText]
public string Text { get; set; }
}
[XmlRoot("properties", Namespace = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata")]
public class Properties
{
[XmlElement("ObjectID", Namespace = "http://schemas.microsoft.com/ado/2007/08/dataservices")]
public ObjectID ObjectID { get; set; }
[XmlElement("ContactID", Namespace = "http://schemas.microsoft.com/ado/2007/08/dataservices")]
public ContactID ContactID { get; set; }
[XmlAttribute("m", Namespace = "http://www.w3.org/2000/xmlns/")]
public string M { get; set; }
}
[XmlRoot("Content")]
public class MyDto
{
[XmlElement("properties", Namespace = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata")]
public Properties Properties { get; set; }
[XmlAttribute("type")]
public string Type { get; set; }
}
Output:
Related
I have the following xml that i want to deserialize to a c# class:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://www.s1.com/info/" xmlns:types="http://www.s1.com/info/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<tns:SessionInfo>
<SessionId xsi:type="xsd:string">string</SessionId>
</tns:SessionInfo>
</soap:Header>
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<tns:LoginResponse>
<Result xsi:type="xsd:boolean">boolean</Result>
</tns:LoginResponse>
</soap:Body>
</soap:Envelope>
I am using the following classes in order to deserialize the xml:
public class SessionId
{
[XmlAttribute(AttributeName = "type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Type { get; set; }
[XmlText]
public string Text { get; set; }
}
[XmlRoot(ElementName = "SessionInfo", Namespace = "http://www.s1.com/info/")]
public class SessionInfo
{
[XmlElement(ElementName = "SessionId")]
public SessionId SessionId { get; set; }
[XmlAttribute(AttributeName = "id", Namespace = "")]
public string Id { get; set; }
[XmlText]
public string Text { get; set; }
}
[XmlRoot(ElementName = "Header", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Header
{
[XmlElement(ElementName = "SessionInfo", Namespace = "http://www.s1.com/info/")]
public SessionInfo SessionInfo { get; set; }
}
[XmlRoot(ElementName = "Result", Namespace = "")]
public class Result
{
[XmlAttribute(AttributeName = "type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Type { get; set; }
[XmlText]
public string Text { get; set; }
}
[XmlRoot(ElementName = "LoginResponse", Namespace = "http://www.s1.com/info/")]
public class LoginResponse
{
[XmlElement(ElementName = "Result")]
public Result Result { get; set; }
}
[XmlRoot(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Body
{
[XmlElement(ElementName = "LoginResponse", Namespace = "http://www.s1.com/info/")]
public LoginResponse LoginResponse { get; set; }
[XmlAttribute(AttributeName = "encodingStyle", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public string EncodingStyle { get; set; }
[XmlText]
public string Text { get; set; }
}
[XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Envelope
{
[XmlElement(ElementName = "Header", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public Header Header { get; set; }
[XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public Body Body { get; set; }
[XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Xsi { get; set; }
[XmlAttribute(AttributeName = "xsd", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Xsd { get; set; }
[XmlAttribute(AttributeName = "soapenc", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Soapenc { get; set; }
[XmlAttribute(AttributeName = "tns", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Tns { get; set; }
[XmlAttribute(AttributeName = "types", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Types { get; set; }
[XmlAttribute(AttributeName = "soap", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Soap { get; set; }
[XmlText]
public string Text { get; set; }
}
The problem is that the SessionId element is not getting deserialized, I am assuming due to the namespaces mismatch. I tried using an empty string as the namespace but that doesn't work either as it doesn't get recognized during deserialization.
Any insight on the problem is very much appreciated. Thank you!
First, SessionId has the wrong namespace. It inherits this from the parent, you need to explicitly specify that it doesn't have one by setting it to an empty string.
Secondly, the xsi:type has a special meaning, you shouldn't try to deserialise this. It's used to indicate the content type of an element - in this case, string - and will be used by the serialiser. The implication is that this is one of many acceptable types. The simplest way to define this is using object.
Putting those together, this should work:
[XmlElement(ElementName = "SessionId", Namespace = "")]
public object SessionId { get; set; }
SessionId should contain a string object with value string.
I'd also note various other minor things:
You shouldn't specify all the namespace bindings (e.g. Xsd) as part of the model. This is lower level than this model and will be handled by the serialiser.
You only need XmlRoot on the root
You don't need XmlText properties where there isn't any text
You need to make a similar change to above to deserialise Result
ElementName and AttributeName will default to the name of the property, so you don't have to specify these if that's what you want
Taking that into account, this model should work:
public class SessionInfo
{
[XmlElement(Namespace = "")]
public object SessionId { get; set; }
}
public class Header
{
[XmlElement(Namespace = "http://www.s1.com/info/")]
public SessionInfo SessionInfo { get; set; }
}
public class LoginResponse
{
[XmlElement(Namespace = "")]
public object Result { get; set; }
}
public class Body
{
[XmlElement(Namespace = "http://www.s1.com/info/")]
public LoginResponse LoginResponse { get; set; }
[XmlAttribute("encodingStyle", Namespace = "http://schemas.xmlsoap.org/soap/envelope/", Form = XmlSchemaForm.Qualified)]
public string EncodingStyle { get; set; }
}
[XmlRoot(Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Envelope
{
[XmlElement]
public Header Header { get; set; }
[XmlElement]
public Body Body { get; set; }
}
You can see a working demo here. I've made one change to the source XML - I changed the Result value from boolean to true, else you'll get an exception because boolean isn't a valid value for that type.
I am trying to serialise a piece of XML that is being returned from a third party API. However when doing so i am only retrieving part of the object upon serialisation. And only some of the values seem to exist. I thought this could be a input type problem, however all the types seem to be correct. I think it may have something to do with how my model is constructed.After debugging the code i have narrowed it down to be a problem with the conversion of the xml into the object.
C# CODE:
//[Route("api/AvailabiliyCheck/GetAvailability/{CSSDistrictCode}/{GoldAddressKey}")]
public EADAvailabilityDetails GetAvailabilityEAD([FromUri] string CSSDistrictCode, [FromUri] string GoldAddressKey)
{
//Load the request xml template
XmlDocument doc = new XmlDocument();
string path = HttpContext.Current.Server.MapPath("~/XML/Availability/GetAvailabilityEAD.xml");
doc.Load(path);
//Assign incoming paramaters to xml template
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
manager.AddNamespace("stupid_xmlns", "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService");
XmlNode CSSDistrictCodeNode = doc.SelectSingleNode("soap:Envelope/soap:Body/stupid_xmlns:GetAvailability/stupid_xmlns:request/stupid_xmlns:RequestDetails/stupid_xmlns:CSSDistrictCode", manager);
CSSDistrictCodeNode.InnerXml = CSSDistrictCode;
XmlNode GoldAddressKeyNode = doc.SelectSingleNode("soap:Envelope/soap:Body/stupid_xmlns:GetAvailability/stupid_xmlns:request/stupid_xmlns:RequestDetails/stupid_xmlns:GoldAddressKey", manager);
GoldAddressKeyNode.InnerXml = GoldAddressKey;
//Send Request To API
string _url = "https://b2b.api.talktalkgroup.com/api/v2/partners/AvailabilityCheckers/NPAC/v45";
string _action = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService/NetworkProductAvailabilityCheckerService/GetAvailability";
string xml = doc.InnerXml;
var soapResult = WebService.ApiRequest(_url, _action, xml);
XmlDocument xmlToFormat = new XmlDocument();
xmlToFormat.LoadXml(soapResult);
string Outerxml = xmlToFormat.FirstChild.FirstChild.FirstChild.FirstChild.ChildNodes[2].InnerXml;
//Remove all namespaces
var xmlToBeStripped = XElement.Parse(Outerxml);
string finalXml = XmlFormatter.stripNS(xmlToBeStripped).ToString();
EADAvailabilityDetails result;
// Deserialises xlm into an object
XmlSerializer serializer = new XmlSerializer(typeof(EADAvailabilityDetails));
using (TextReader reader = new StringReader(finalXml))
{
result = (EADAvailabilityDetails)serializer.Deserialize(reader);
}
return result;
}
XML being returned:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetAvailabilityResponse xmlns="http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService">
<GetAvailabilityResult xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Status xmlns="http://schemas.datacontract.org/2004/07/InHouse.SharedLibraries.ServiceBase.BaseTypes">
<Errors/>
<HasErrors>false</HasErrors>
</Status>
<CSSDistrictCode>lv</CSSDistrictCode>
<EADAvailability>
<AvailabilityDetails i:type="EADAvailabilityDetails">
<Status xmlns="http://schemas.datacontract.org/2004/07/InHouse.SharedLibraries.ServiceBase.BaseTypes">
<Errors/>
<HasErrors>false</HasErrors>
</Status>
<EADAvailability>
<EADAvailabilityResult>
<CollectorNodeExchangeCode>NDMAI</CollectorNodeExchangeCode>
<CollectorNodeExchangeName>Maidstone</CollectorNodeExchangeName>
<Distance>0</Distance>
<EADBandwidth xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:string>100M</a:string>
</EADBandwidth>
<EADSubType>EAD-LA</EADSubType>
<FibreExchangeCode>NDACO</FibreExchangeCode>
<FibreExchangename>Archers Court</FibreExchangename>
<IndicativeECC>Within tariff</IndicativeECC>
<IndicativeOrderCategory>Category 2.1</IndicativeOrderCategory>
<LocalExchangeCode>NDACO</LocalExchangeCode>
<LocalExchangeName>Archers Court</LocalExchangeName>
<ORLeadTime>40</ORLeadTime>
<OrderCategoryExplanation>There is a T node within 1km (or 650m in London) with spare capacity and ducting is in place, however some additional cabling is required between the premises and the T node.</OrderCategoryExplanation>
<TTLeadTime>56</TTLeadTime>
<Zone>0</Zone>
</EADAvailabilityResult>
<EADAvailabilityResult>
<CollectorNodeExchangeCode>NDMAI</CollectorNodeExchangeCode>
<CollectorNodeExchangeName>Maidstone</CollectorNodeExchangeName>
<Distance>0</Distance>
<EADBandwidth xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:string>LOW 1GB</a:string>
</EADBandwidth>
<EADSubType>EAD-LA</EADSubType>
<FibreExchangeCode>NDACO</FibreExchangeCode>
<FibreExchangename>Archers Court</FibreExchangename>
<IndicativeECC>Within tariff</IndicativeECC>
<IndicativeOrderCategory>Category 2.1</IndicativeOrderCategory>
<LocalExchangeCode>NDACO</LocalExchangeCode>
<LocalExchangeName>Archers Court</LocalExchangeName>
<ORLeadTime>40</ORLeadTime>
<OrderCategoryExplanation>There is a T node within 1km (or 650m in London) with spare capacity and ducting is in place, however some additional cabling is required between the premises and the T node.</OrderCategoryExplanation>
<TTLeadTime>56</TTLeadTime>
<Zone>0</Zone>
</EADAvailabilityResult>
<EADAvailabilityResult>
<CollectorNodeExchangeCode>NDCAN</CollectorNodeExchangeCode>
<CollectorNodeExchangeName>Canterbury</CollectorNodeExchangeName>
<Distance>20656</Distance>
<EADBandwidth xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:string>HIGH 1GB</a:string>
</EADBandwidth>
<EADSubType>EAD-NonLA</EADSubType>
<FibreExchangeCode>NDCAN</FibreExchangeCode>
<FibreExchangename>Canterbury</FibreExchangename>
<IndicativeECC>Within tariff</IndicativeECC>
<IndicativeOrderCategory>Category 2.1</IndicativeOrderCategory>
<LocalExchangeCode>NDACO</LocalExchangeCode>
<LocalExchangeName>Archers Court</LocalExchangeName>
<ORLeadTime>40</ORLeadTime>
<OrderCategoryExplanation>There is a T node within 1km (or 650m in London) with spare capacity and ducting is in place, however some additional cabling is required between the premises and the T node.</OrderCategoryExplanation>
<TTLeadTime>56</TTLeadTime>
<Zone>B</Zone>
</EADAvailabilityResult>
</EADAvailability>
<LeadTime>10</LeadTime>
</AvailabilityDetails>
</EADAvailability>
<GoldAddressKey>A00009292752</GoldAddressKey>
<Postcode/>
</GetAvailabilityResult>
</GetAvailabilityResponse>
</s:Body>
</s:Envelope>
Model:
[Serializable, XmlRoot("AvailabilityDetails")]
public class EADAvailabilityDetails
{
[XmlElement("EADAvailability")]
public EADAvailability EADAvailability { get; set; }
}
public class EADAvailability
{
[XmlElement("EADAvailabilityResult")]
public List<EADAvailabilityResult> EADAvailabilityResult { get; set; }
}
public class EADAvailabilityResult
{
[XmlElement("CollectorNodeExchangeCode")]
public string CollectorNodeExchangeCode { get; set; }
[XmlElement("CollectorNodeExchangeName")]
public string CollectorNodeExchangeName { get; set; }
[XmlElement("Distance")]
public int Distance { get; set; }
[XmlElement("EADBandwidth")]
public string EADBandwidth { get; set; }
[XmlElement("EADSubType")]
public string EADSubType { get; set; }
[XmlElement("FibreExchangeCode")]
public string FibreExchangeCode { get; set; }
[XmlElement("FibreExchangename")]
public string FibreExchangename { get; set; }
[XmlElement("IndicativeECC")]
public string IndicativeECC { get; set; }
[XmlElement("IndicativeOrderCategory")]
public string IndicativeOrderCategory { get; set; }
[XmlElement("LocalExchangeCode")]
public string LocalExchangeCode { get; set; }
[XmlElement("LocalExchangeName")]
public string LocalExchangeName { get; set; }
[XmlElement("ORLeadTime")]
public int ORLeadTime { get; set; }
[XmlElement("OrderCategoryExplanation")]
public string OrderCategoryExplanation { get; set; }
[XmlElement("TTLeadTime")]
public int TTLeadTime { get; set; }
[XmlElement("Zone")]
public int Zone { get; set; }
}
XML after serialisation:
{
"<EADAvailability>k__BackingField": {
"EADAvailabilityResult": [
{
"CollectorNodeExchangeCode": "NDMAI",
"CollectorNodeExchangeName": "Maidstone",
"Distance": 0,
"EADBandwidth": "100M",
"EADSubType": null,
"FibreExchangeCode": null,
"FibreExchangename": null,
"IndicativeECC": null,
"IndicativeOrderCategory": null,
"LocalExchangeCode": null,
"LocalExchangeName": null,
"ORLeadTime": 0,
"OrderCategoryExplanation": null,
"TTLeadTime": 0,
"Zone": 0
}
]
}
}
The code below works :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication139
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(Envelope));
Envelope envelope = (Envelope)serializer.Deserialize(reader);
}
}
[XmlRoot(Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Envelope
{
[XmlElement (Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public Body Body { get; set; }
}
public class Body
{
[XmlElement(Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
public GetAvailabilityResponse GetAvailabilityResponse { get; set; }
}
public class GetAvailabilityResponse
{
[XmlElement(Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
public GetAvailabilityResult GetAvailabilityResult { get; set; }
}
public class GetAvailabilityResult
{
[XmlArray("EADAvailability", Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
[XmlArrayItem("AvailabilityDetails", Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
public AvailabilityDetails[] AvailabilityDetails { get; set; }
}
[XmlInclude(typeof(EADAvailabilityDetails))]
[Serializable, XmlRoot("AvailabilityDetails", Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
public class AvailabilityDetails
{
}
[Serializable, XmlRoot("EADAvailabilityDetails", Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
public class EADAvailabilityDetails : AvailabilityDetails
{
[XmlArray("EADAvailability", Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
[XmlArrayItem("EADAvailabilityResult", Namespace = "http://webservices.talktalkplc.com/NetworkProductAvailabilityCheckerService")]
public EADAvailabilityResult[] EADAvailabilityResult { get; set; }
}
public class EADAvailabilityResult
{
public string CollectorNodeExchangeCode { get; set; }
public string CollectorNodeExchangeName { get; set; }
public int Distance { get; set; }
public EADBandwidth EADBandwidth { get; set; }
public string EADSubType { get; set; }
public string FibreExchangeCode { get; set; }
public string FibreExchangename { get; set; }
public string IndicativeECC { get; set; }
public string IndicativeOrderCategory { get; set; }
public string LocalExchangeCode { get; set; }
public string LocalExchangeName { get; set; }
public int ORLeadTime { get; set; }
public string OrderCategoryExplanation { get; set; }
public int TTLeadTime { get; set; }
public string Zone { get; set; }
}
public class EADBandwidth
{
[XmlElement(ElementName = "string", Type = typeof(string), Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
public string String { get; set; }
}
}
When I deserialize the XML below, from a third-party, my objects are always null.
XML
<?xml version="1.0"?>
<OrderImport xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Reply i:nil="true">
</Reply>
<ReplyStatus i:nil="true">
<DebugInfo>
</DebugInfo>
<PerformanceLogInfo>
</PerformanceLogInfo>
</ReplyStatus>
<Reply>
<OrderNumber>4063286</OrderNumber>
</Reply>
<ReplyStatus>
<Result>0</Result>
<Message>
</Message>
</ReplyStatus>
</OrderImport>
C# Class
[XmlRoot(ElementName = "OrderImport")]
public class OrderImport
{
[XmlElement(ElementName = "Reply")]
public List<Reply> Reply { get; set; }
[XmlElement(ElementName = "ReplyStatus")]
public List<ReplyStatus> ReplyStatus { get; set; }
[XmlAttribute(AttributeName = "i", Namespace = "http://www.w3.org/2000/xmlns/")]
public string I { get; set; }
}
[XmlRoot(ElementName= "Reply")]
public class Reply
{
[XmlAttribute(AttributeName = "nil", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Nil { get; set; }
[XmlElement(ElementName = "OrderNumber")]
public string OrderNumber { get; set; }
}
[XmlRoot(ElementName = "ReplyStatus")]
public class ReplyStatus
{
[XmlElement(ElementName = "DebugInfo")]
public string DebugInfo { get; set; }
[XmlElement(ElementName = "PerformanceLogInfo")]
public string PerformanceLogInfo { get; set; }
[XmlAttribute(AttributeName = "nil", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Nil { get; set; }
[XmlElement(ElementName = "Result")]
public string Result { get; set; }
[XmlElement(ElementName = "Message")]
public string Message { get; set; }
}
I believe the problem has to do with the first occurrence of the objects Reply and ReplyStatus being null.
I'm trying to deserialize like so
httpResponseMessage.Content.ReadAsAsync<OrderImport>().Result;
However, I've found that if I deserialize like this it works just fine
stringres = httpResponseMessage.Content.ReadAsStringAsync().Result;
using (var stringreader = new StringReader(stringres))
{
var result = (OrderImport)xmlSerializer.Deserialize(stringreader);
}
I'm trying to parse an XML response from a REST endpoint. I am using a POST request (if that's relevant). I can't get the document to parse correctly. I've researched this all over stack overflow, and none seem to be applicable to my response. How can i parse my XML? I've tried all of the below:
Using XDocument:
Stream postData = resp.GetResponseStream();
StreamReader reader = new StreamReader(postData, Encoding.UTF8);
string result = reader.ReadToEnd();
var document = XDocument.Parse(result);
XNamespace ns = XNamespace.Get("http://www.w3.org/2005/Atom");
var items = document.Descendants("NameFirst")
.ToDictionary(i => (string)i.Attribute("Key"),
i => (string)i.Attribute("Value"));
Using nested for each with XElements:
Stream postData = resp.GetResponseStream();
StreamReader reader = new StreamReader(postData, Encoding.UTF8);
string result = reader.ReadToEnd();
XDocument document = XDocument.Parse(result);
XNamespace ns = XNamespace.Get("http://www.w3.org/2005/Atom");
string list = "";
foreach (XElement level1 in document.Elements("feed"))
{
foreach (XElement level2 in level1.Elements("entry"))
{
foreach (XElement level3 in level2.Elements("content"))
{
foreach (XElement entry in level3.Elements("Entry"))
{
list += entry.Attribute("NameFirst").Value;
list += entry.Attribute("NameLast").Value;
}
}
}
}
Using a concatenation of Descendant methods:
Stream postData = resp.GetResponseStream();
StreamReader reader = new StreamReader(postData, Encoding.UTF8);
string result = reader.ReadToEnd();
var document = XDocument.Parse(result);
XNamespace ns = XNamespace.Get("http://www.w3.org/2005/Atom");
var listOfFields = document.Descendants(ns + "feed").Descendants(ns + "entry").Descendants(ns + "content").Descendants(ns + "entry").Select(x => x.Elements().First().Value).ToList();
ResultLabel.Text = "";
foreach(String item in listOfFields){
ResultLabel.Text += item;
}
Using multiple Element methods:
Stream postData = resp.GetResponseStream();
StreamReader reader = new StreamReader(postData, Encoding.UTF8);
string result = reader.ReadToEnd();
var document = XDocument.Parse(result);
XNamespace ns = XNamespace.Get("http://www.w3.org/2005/Atom");
var listOfFields = document.Descendants(ns + "feed").Descendants(ns + "entry").Descendants(ns + "content").Descendants(ns + "entry").Select(x => x.Elements().First().Value).ToList();
var entry_ = document.Root.Element("entry");
var content = entry_.Element("content");
var entry = content.Element("Entry");
var fname = entry.Element("NameFirst").Value;
var lname = entry.Element("NameLast").Value;
ResultLabel.Text = string.Join(",", lname, fname);
My XML response:
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title type="text">Search Results</title>
<id>https://myendpoint.com/Rest/services/select/Entry</id>
<updated>2015-10-07T09:51:32Z</updated>
<link rel="self" type="application/atom+xml" href="https://myendpoint.com/Rest/services/select/Entry" />
<entry>
<id>https://myendpoint.com/services/select/Entry/26032</id>
<title type="text">Smith, John</title>
<published>2013-10-08T10:14:20Z</published>
<updated>2015-10-02T12:14:18Z</updated>
<contributor><name>WebUser</name></contributor>
<content type="xhtml">
<Entry>
<EntryID>26032</EntryID>
<CategoryID>0</CategoryID>
<EventID>0</EventID>
<GroupID>0</GroupID>
<ContactID>0</ContactID>
<AddressTypeID>0</AddressTypeID>
<PinNumber>0000</PinNumber>
<Password></Password>
<PortalEmail></PortalEmail>
<NameLast>Smith</NameLast>
<NameFirst>John</NameFirst>
<NameTitle></NameTitle>
<NamePreferred>Mike</NamePreferred>
<NameWeb>smith</NameWeb>
<NameOther></NameOther>
<NameInitials></NameInitials>
<NameSharer></NameSharer>
<GenderEnum>Female</GenderEnum>
<Birth_GenderEnum>Male</Birth_GenderEnum>
<DirectoryFlagPrivacy>false</DirectoryFlagPrivacy>
<Position></Position>
<ID1>123456</ID1>
<ID2>smith</ID2>
<ID3></ID3>
<ID4>0</ID4>
<ID5>0</ID5>
<PhoneProcessToAccount>true</PhoneProcessToAccount>
<PhoneChargeTypeID>0</PhoneChargeTypeID>
<PhoneDisableValue>0</PhoneDisableValue>
<PhoneRestrictValue>0</PhoneRestrictValue>
<PhoneControlEnum>Default</PhoneControlEnum>
<TaxExemptionEnum>None</TaxExemptionEnum>
<Testing>true</Testing>
<timestamp>000007975236</timestamp>
</Entry>
</content>
</entry>
</feed>
You can deserialize the XML into easily accessible objects. Here's how to do it:
Create the objects that will hold your deserialized data:
You can easily do it by copying the XML you're getting from your REST endpoint then in Visual Studio go to Edit -> Paste Special -> Paste XML as classes
Once your classes are created you will get something like this:
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2005/Atom")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.w3.org/2005/Atom", IsNullable = false)]
public partial class feed
{
public feedTitle title { get; set; }
public string id { get; set; }
public System.DateTime updated { get; set; }
public feedLink link { get; set; }
public feedEntry entry { get; set; }
}
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2005/Atom")]
public partial class feedTitle
{
[System.Xml.Serialization.XmlAttributeAttribute()]
public string type { get; set; }
[System.Xml.Serialization.XmlTextAttribute()]
public string Value { get; set; }
}
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2005/Atom")]
public partial class feedLink
{
[System.Xml.Serialization.XmlAttributeAttribute()]
public string rel { get; set; }
[System.Xml.Serialization.XmlAttributeAttribute()]
public string type { get; set; }
[System.Xml.Serialization.XmlAttributeAttribute()]
public string href { get; set; }
}
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2005/Atom")]
public partial class feedEntry
{
public string id { get; set; }
public feedEntryTitle title { get; set; }
public System.DateTime published { get; set; }
public System.DateTime updated { get; set; }
public feedEntryContributor contributor { get; set; }
public feedEntryContent content { get; set; }
}
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2005/Atom")]
public partial class feedEntryTitle
{
[System.Xml.Serialization.XmlAttributeAttribute()]
public string type { get; set; }
[System.Xml.Serialization.XmlTextAttribute()]
public string Value { get; set; }
}
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2005/Atom")]
public partial class feedEntryContributor
{
public string name { get; set; }
}
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2005/Atom")]
public partial class feedEntryContent
{
public feedEntryContentEntry Entry { get; set; }
[System.Xml.Serialization.XmlAttributeAttribute()]
public string type { get; set; }
}
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2005/Atom")]
public partial class feedEntryContentEntry
{
public ushort EntryID { get; set; }
public byte CategoryID { get; set; }
public byte EventID { get; set; }
public byte GroupID { get; set; }
public byte ContactID { get; set; }
public byte AddressTypeID { get; set; }
public byte PinNumber { get; set; }
public object Password { get; set; }
public object PortalEmail { get; set; }
public string NameLast { get; set; }
public string NameFirst { get; set; }
public object NameTitle { get; set; }
public string NamePreferred { get; set; }
public string NameWeb { get; set; }
public object NameOther { get; set; }
public object NameInitials { get; set; }
public object NameSharer { get; set; }
public string GenderEnum { get; set; }
public string Birth_GenderEnum { get; set; }
public bool DirectoryFlagPrivacy { get; set; }
public object Position { get; set; }
public uint ID1 { get; set; }
public string ID2 { get; set; }
public object ID3 { get; set; }
public byte ID4 { get; set; }
public byte ID5 { get; set; }
public bool PhoneProcessToAccount { get; set; }
public byte PhoneChargeTypeID { get; set; }
public byte PhoneDisableValue { get; set; }
public byte PhoneRestrictValue { get; set; }
public string PhoneControlEnum { get; set; }
public string TaxExemptionEnum { get; set; }
public bool Testing { get; set; }
public uint timestamp { get; set; }
}
Then you can deserialize the XML into a feed object like the following:
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("Your XML string here")))
{
XmlSerializer serializer = new XmlSerializer(typeof(feed));
feed feedObject = (feed)serializer.Deserialize(ms);
// Then you can access the xml content like you do with any object.
Console.WriteLine(feedObject.title.Value);
}
Live demo
I am trying to deserialize some xml. Here it is:
<FooBars xmlns="http://foos">
<Id1 xmlns="http://bars">2</Id1>
<Id2 xmlns="http://bars">7</Id2>
<Info xmlns="http://bars">
<Data>
<Field1>text1</Field1>
<Field2>text2</Field2>
<Field3>text3</Field3>
</Data>
<Data>
<Field1>text5</Field1>
<Field2>text6</Field2>
<Field3>text7</Field3>
</Data>
</Info>
</FooBars>
I tried this:
var myData = (FooBars)serializer.Deserialize(foobars.CreateReader());
...
[XmlRoot(ElementName = "FooBars", Namespace = "http://foos")]
public class FooBars
{
[XmlElement(ElementName = "Id1", Namespace = "http://bars")]
public string Id1 { get; set; }
[XmlElement(ElementName = "Id2", Namespace = "http://bars")]
public string Id2 { get; set; }
[XmlElement(ElementName = "Info", Namespace = "http://bars")]
public List<Data> Info { get; set; }
}
public class Data
{
[XmlElement(ElementName = "Field1")]
public string Field1 { get; set; }
[XmlElement(ElementName = "Field2")]
public string Field2 { get; set; }
}
But it looks like the Data class is not considered part of the xml, since it is not able to read it. I am getting all the other elements (ids) but not the things defined in Data.
Where am I wrong?
Presuming missing </Info> tag is a typo, All you need is XmlArray and XmlArrayItem
[XmlRoot(ElementName = "FooBars", Namespace = "http://foos")]
public class FooBars
{
[XmlElement(ElementName = "Id1", Namespace = "http://bars")]
public string Id1 { get; set; }
[XmlElement(ElementName = "Id2", Namespace = "http://bars")]
public string Id2 { get; set; }
[XmlArray(ElementName = "Info", Namespace = "http://bars"), XmlArrayItem("Data")] //<--
public List<Data> Info { get; set; }
}
The XML is missing a closing tag for Info. Also, you need to defined the Field3 property in the Data class and add the namespace 'http://bars' to it.
If your xml is missing the info closing tag, meant to contain the Data elements then your classes should look something like:
[XmlRoot(ElementName = "FooBars", Namespace = "http://foos")]
public class FooBars
{
[XmlElement(ElementName = "Id1", Namespace = "http://bars")]
public string Id1 { get; set; }
[XmlElement(ElementName = "Id2", Namespace = "http://bars")]
public string Id2 { get; set; }
[XmlElement(ElementName = "Info", Namespace = "http://bars")]
public Info Information { get;set; }
}
public class Info {
[XmlElement(ElementName = "Data", Namespace = "")]
public Info[] Info { get; set; }
}
public class Data
{
[XmlElement(ElementName = "Field1")]
public string Field1 { get; set; }
[XmlElement(ElementName = "Field2")]
public string Field2 { get; set; }
}
Notice how in your xml the info object basically contains all the data, not the FooBars like you designed the classes.
via LinqPad - you can see the Field properties are null in the myData.Info property, and that is your problem, right? UPDATED:
void Main()
{
string xmlString;
string path = #"C:\Temp\exampleXmlSO.xml";
using (StreamReader streamReader = File.OpenText(path))
{
xmlString = streamReader.ReadToEnd();
}
XmlSerializer serializer = new XmlSerializer(typeof(FooBars));
using (StringReader stringReader = new StringReader(xmlString))
{
var myData = (FooBars)serializer.Deserialize(stringReader);
Console.WriteLine(myData);
}
}
[XmlRoot(ElementName = "FooBars", Namespace = "http://foos")]
public class FooBars
{
[XmlElement(ElementName = "Id1", Namespace = "http://bars")]
public string Id1 { get; set; }
[XmlElement(ElementName = "Id2", Namespace = "http://bars")]
public string Id2 { get; set; }
[XmlArray(ElementName = "Info", Namespace = "http://bars"), XmlArrayItem("Data")] //<--
public List<Data> Info { get; set; }
}
[Serializable]
public class Data
{
[XmlElement(ElementName = "Field1")]
public string Field1 { get; set; }
[XmlElement(ElementName = "Field2")]
public string Field2 { get; set; }
[XmlIgnore]
public string Field3 { get; set; }
}