This is the xml stream:
<?xml version="1.0" encoding="utf-8" ?>
<historydetails>
<taskEvent>
<eventtype>Transitions</eventtype>
<historyevent>Task moved</historyevent>
<details>From 'Requested' to 'In Validation'</details>
<author>NAme</author>
<entrydate>01 Jul 13, 11:34</entrydate>
<historyid>2620</historyid>
</taskEvent>
<taskEvent>
<eventtype>Updates</eventtype>
<historyevent>Subtask marked done</historyevent>
<details>Subtask: visualise status and versions</details>
<author>NAme2</author>
<entrydate>21 Jun 13, 10:16</entrydate>
<historyid>2588</historyid>
</taskEvent>
</historydetails>
The corresponding classes look like this:
public class historydetails
{
[XmlElement("taskEvent")]
List<taskEvent> eventList = new List<taskEvent>();
}
public class taskEvent
{
string eventtype { get; set; }
string historyevent { get; set; }
string details { get; set; }
string author { get; set; }
string entrydate { get; set; }
string historyid { get; set; }
}
the code to deserialise the xml (the string replacement contains the xml code):
XmlSerializer deserializer = new XmlSerializer(typeof(historydetails));
object obj = obj = deserializer.Deserialize(stringToStream(replacement));
historydetails XmlData = (historydetails)obj;
The method stringToStream
private MemoryStream stringToStream(string input)
{
byte[] byteArray = Encoding.ASCII.GetBytes(input);
MemoryStream stream = new MemoryStream(byteArray);
return stream;
}
The result that i get is as following:
The object XmlData is made and there is a list of taskEvents.
The problem is in the list itself: it is empty...
You have to make the members public
public class historydetails
{
[XmlElement("taskEvent")]
public List<taskEvent> eventList = new List<taskEvent>();
}
public class taskEvent
{
public string eventtype { get; set; }
public string historyevent { get; set; }
public string details { get; set; }
public string author { get; set; }
public string entrydate { get; set; }
public string historyid { get; set; }
}
As an aside, for future reference (with Visual Studio 2012 or the WebEssentials plugin), one of the easiest way to create the classes based on some sample XML content data is to copy it into the clipboard and then use the built-in VS function: EDIT - > Paste Special -> Paste XML As Classes into a new class file.
It leaves less space for errors like the one you encountered and
It's fast, you'll have your classes ready in a few seconds
Related
I have a response from Jira API, require to be deserialized into data model:
com.atlassian.greenhopper.service.sprint.Sprint#40675167[id=10151,rapidViewId=171,state=CLOSED,name=Sprint 37.1,startDate=2015-07-30T16:00:22.000+03:00,endDate=2015-08-13T16:00:00.000+03:00,completeDate=2015-08-13T14:31:34.343+03:00,sequence=10151]
This is actually the information of current sprint for issue.
I need to deserialize it to a model like:
public class Model
{
public string name { get; set; }
...
}
I have already removed all non-required information, like com.atlassian.greenhopper.service.sprint.Sprint#40675167 using Regex pattern \[(.*?)\] so I have brackets and all inside.
Now I stopped completely trying to find the a way to convert this string to a data model.
Found the following thread at the Atlassian Answers page and there appears to be no JSON representation of that inner Object. As shown in the example from that thread:
customfield_10007:[
"com.atlassian.greenhopper.service.sprint.Sprint#a29f07[rapidViewId=<null>,state=CLOSED,name=NORD - Sprint 42,startDate=2013-07-29T06:47:00.000+02:00,endDate=2013-08-11T20:47:00.000+02:00,completeDate=2013-08-14T15:31:33.157+02:00,id=107]",
"com.atlassian.greenhopper.service.sprint.Sprint#769133[rapidViewId=<null>,state=ACTIVE,name=NORD - Sprint 43,startDate=2013-08-14T15:32:47.322+02:00,endDate=2013-08-23T15:32:47.322+02:00,completeDate=<null>,id=117]"
],
The response is indeed a JSON array, but the array itself contains CSV's, so you can make use of the following to parse that:
public class DataObject
{
public string id { get; set; }
public string rapidViewId { get; set; }
public string state { get; set; }
public string name { get; set; }
public string startDate { get; set; }
public string endDate { get; set; }
public string completeDate { get; set; }
public string sequence { get; set; }
}
public class Program
{
private const string sampleStringData =
#"[id=10151,rapidViewId=171,state=CLOSED,name=Sprint 37.1,startDate=2015-07-30T16:00:22.000+03:00,endDate=2015-08-13T16:00:00.000+03:00,completeDate=2015-08-13T14:31:34.343+03:00,sequence=10151]";
static void Main(string[] args)
{
var dataObject = new DataObject();
string[][] splitted;
var sampleWithNoBrackets = sampleStringData.Substring(1,sampleStringData.Length-2);
splitted = sampleWithNoBrackets.Split(',').Select(p => p.Split('=')).ToArray();
dataObject.id = splitted[0][1];
dataObject.rapidViewId = splitted[1][1];
dataObject.state = splitted[2][1];
dataObject.name = splitted[3][1];
dataObject.startDate = splitted[4][1];
dataObject.endDate = splitted[5][1];
dataObject.completeDate = splitted[6][1];
dataObject.sequence = splitted[7][1];
Console.ReadKey();
}
}
Here's the output for the above:
I have an XML snippet like so:
<coverageCd>WEL
<descriptorCd>SMIO
<descriptorCdStartDate>01/01/2015</descriptorCdStartDate>
<descriptorCdEndDate>12/31/9999</descriptorCdEndDate>
</descriptorCd>
<descriptorCd>AAE
<descriptorCdStartDate>01/01/2015</descriptorCdStartDate>
<descriptorCdEndDate>12/31/9999</descriptorCdEndDate>
</descriptorCd>
</coverageCd>
I need to automagically translate this into the following class structure:
public class XmlCoverageCode
{
public string CoverageCode { get; set; }
public IEnumerable<XmlDescriptor> Descriptors { get; set; }
}
public class XmlDescriptor
{
public string DescriptorCode { get; set; }
public string DescriptorCodeStartDate { get; set; }
public string DescriptorCodeEndDate { get; set; }
}
...so the above XML snippet would translate to this:
var coverageCd = new XmlCoverageCode
{
CoverageCode = "WEL",
Descriptors =
new List<XmlDescriptor>
{
new XmlDescriptor
{
DescriptorCode = "SMIO",
DescriptorCodeStartDate = "01/01/2015",
DescriptorCodeEndDate = "12/31/9999"
},
new XmlDescriptor
{
DescriptorCode = "AAE",
DescriptorCodeStartDate = "01/01/2015",
DescriptorCodeEndDate = "12/31/9999"
}
}
};
Naturally, I would prefer to use built-in mechanisms for doing this. I just don't know if that's even possible.
To get classes from the XML, you can just copy your XML into clipboard and make Edit -> Paste Special -> Paste XML As Classes in Visual Studio. Then, after cleaning up of generated code, we get the following:
[XmlRoot(ElementName = "coverageCd")]
public partial class XmlCoverageCode
{
[XmlText]
public string CoverageCode { get; set; }
[XmlElement("descriptorCd")]
public List<XmlDescriptor> Descriptors { get; set; }
}
public partial class XmlDescriptor
{
[XmlText]
public string DescriptorCode { get; set; }
[XmlElement("descriptorCdStartDate")]
public string DescriptorCodeStartDate { get; set; }
[XmlElement("descriptorCdEndDate")]
public string DescriptorCodeEndDate { get; set; }
}
This is actually the same, as you wrote in the question, but with the required attributes and changed IEnumerable to List, because XmlSerializer doesn't support the first one.
And the code snippet how to serialize/deserialize:
var serializer = new XmlSerializer(typeof(XmlCoverageCode));
var coverageCode = (XmlCoverageCode)serializer.Deserialize(xmlFileStream);
serializer.Serialize(xmlFileStream, coverageCode);
You can use xsd command for converting xml to c# class
Save the xml in the file test.xml
Run xsd.exe test.xml to generate a schema e.g. test.xsd
Run xsd.exe /c test.xsd to generate classes from the schema
I have an object that has some properties that are XML string fragments. I want to take those and further deserialize them into objects for easier use. How can I do that using the .NET XML Serializer?
Here's an example of the XML string fragment:
<Addr1></Addr1>
<Addr2></Addr2>
<Addr3></Addr3>
<Addr4></Addr4>
<City></City>
<State></State>
<PostalCode></PostalCode>
<Country></Country>
So far my attempts have resulted in this exception:
<Addr1 xmlns=''> was not expected.
If you want to deserialize the fragments into objects I assume you have a strongly typed object so you could just create a helper method to add a root element using the type name of the object you are trying to deserialize
Example:
public T DeserializeFragment<T>(string xmlFragment)
{
// Add a root element using the type name e.g. <MyData>...</MyData>
var xmlData = string.Format("<{0}>{1}</{0}>", typeof(T).Name, xmlFragment);
var mySerializer = new XmlSerializer(typeof(T));
using (var reader = new StringReader(xmlData))
{
return (T)mySerializer.Deserialize(reader);
}
}
Usage:
public class MyData
{
public string Addr1 { get; set; }
public string Addr2 { get; set; }
public string Addr3 { get; set; }
public string Addr4 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
}
string fragment = #"<Addr1>2</Addr1>
<Addr2>2</Addr2>
<Addr3>2</Addr3>
<Addr4>2</Addr4>
<City>2</City>
<State>2</State>
<PostalCode>2</PostalCode>
<Country>2</Country>";
var result = DeserializeFragment<MyData>(fragment);
can you help me?
I have small experience in xml-serialization and can't resolve this problem.
I create request and get an answer
I have xml-response like this(from debug):
<?xml version=\"1.0\" encoding=\"utf-8\"?>\n
<SpellResult>
<error code=\"1\" pos=\"0\" row=\"0\" col=\"0\" len=\"6\">
<word>wird</word>
<s>word</s>
<s>world</s>
...
</error>
</SpellResult>
my deserialization:
...
var deserializer = new XmlSerializer(typeof(T));
using (MemoryStream memoryStream = new MemoryStream(StringToUtf8ByteArray(response.ToString())))
{
memoryStream.Position = 0;
var result = (T)deserializer.Deserialize(memoryStream);
return result;
}
...
Where:
private Byte[] StringToUtf8ByteArray(string xmlString)
{
// UTF8Encoding encoding = new UTF8Encoding();
var byteArray = Encoding.UTF8.GetBytes(xmlString);
return byteArray;
}
This is T-type:
[Serializable()]
[XmlRoot("SpellResult")]
public class SpellResult
{
public List<error> Errors
{
get;
set;
}
}
[Serializable()]
public class error
{
[XmlAttribute("code")]
public int Code
{
get;
set;
}
[XmlAttribute("pos")]
public int Position
{
get;
set;
}
[XmlAttribute("row")]
public int Row
{
get;
set;
}
[XmlAttribute("col")]
public int Column
{
get;
set;
}
[XmlAttribute("len")]
public int Length
{
get;
set;
}
[XmlElement("word")]
public string Word
{
get;
set;
}
[XmlArray]
[XmlArrayItem("s", typeof(Steer))]
public Steer[] Steer
{
get;
set;
}
}
[Serializable()]
public class Steer
{
[XmlElementAttribute("s")]
public string s { get; set; }
}
And I have exception: {"Data at the root level is invalid. Line 1, position 1."}
I tried to fix this problem with any answers from SO and other sites, but they do not resolve the issue.
To help diagnose errors like this, try to create an instance of the class, containing the data that you expected to get from your input XML. Then serialize your instance, and look at the results. This will tell you how XML Serialization expects your data to appear.
I suspect that you are missing an <Errors> element.
You class hierarchy, if you want to have Steer as class, must looks like this:
public class SpellResult
{
[XmlElement("error")]
public List<Error> Errors { get; set; }
}
public class Error
{
[XmlAttribute("code")]
public int Code { get; set; }
[XmlAttribute("pos")]
public int Position { get; set; }
[XmlAttribute("row")]
public int Row { get; set; }
[XmlAttribute("col")]
public int Column { get; set; }
[XmlAttribute("len")]
public int Length { get; set; }
[XmlElement("word")]
public string Word { get; set; }
[XmlElement("s")]
public List<Steer> Steers { get; set; }
}
public class Steer
{
[XmlText]
public string S { get; set; }
}
or, you can avoid class Steer just deserialize s elements into list of strings
[XmlElement("s")]
public List<string> Steers { get; set; }
Oh,
It was my carelessness and simple mistake.
I wrote
MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(responce))
But responce is an object of RestResponse...
Where I wrote:
string resp = response.Content.ToString();
using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(resp)))
{
...
}
It's worked. Facepalm.
Thanks for help.
I have run into a problem while trying to parse the response of a WebDAV application.
The relevant part of the response looks like this:
for collections:
....
<D:getlastmodified xmlns:B="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/" B:dt="dateTime.rfc1123">Tue, 15 Jan 2013 15:47:30 GMT</D:getlastmodified>
<D:displayname>aaa.bc</D:displayname>
<D:resourcetype>
<D:collection />
</D:resourcetype>
<D:getcontenttype>text/html; charset=utf-8</D:getcontenttype>
....
for normal files:
....
<D:getlastmodified xmlns:B="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/" B:dt="dateTime.rfc1123">Tue, 15 Jan 2013 15:47:30 GMT</D:getlastmodified>
<D:displayname>aaa.bc</D:displayname>
<D:resourcetype />
<D:getcontenttype>text/html; charset=utf-8</D:getcontenttype>
....
I want to parse this into a c# object with the property:
[XmlElement("resourcetype")]
public string Type {get;set;}
Where e.g. Type = "collection" for a collection.
How would I do this? For the part I posted my C# code looks like this (but does not do what I want):
[XmlRoot("prop")]
public class Prop
{
[XmlElement("creationdate")]
public string CreationDate { get; set; }
[XmlElement("getlastmodified")]
public string LastModified { get; set; }
[XmlElement("displayname")]
public string DisplayName { get; set; }
[XmlElement("resourcetype")]
public string ResourceType { get; set; }
[XmlElement("getcontenttype")]
public string ContentType { get; set; }
[XmlElement("getcontentlength")]
public string ContentLength { get; set; }
[XmlElement("getetag")]
public string ETag { get; set; }
[XmlElement("imagewidth")]
public string ImageWidth { get; set; }
[XmlElement("imageheight")]
public string ImageHeight { get; set; }
[XmlElement("thumbnailuri")]
public string TumbnailUri { get; set; }
}
[XmlRoot("resourcetype")]
public class ResourceType
{
[XmlElement("collection")] // TODO
public string Collection { get; set; }
}
and the method to parse everything:
private T ParseWebDavXml<T>(string xml)
{
using (var reader = XmlReader.Create(new StringReader(xml)))
{
var serializer = new XmlSerializer(typeof(T), "DAV:");
var result = (T)serializer.Deserialize(reader);
return result;
}
}
Check this Link: I have tested this code
Remove the FirtsColumn, SecondColumn from the code and utilize the xmlDS as per your requirements
XML Parsing
You can change the string type to an object type for the ResourceType fied. You also need to decorate ResourceType fied with XmlType attributes. You specify on XmlType attribute by target (in your case, 2).
You also need to create two types :
One for the string,
One for the collection.
But you can use two more simpler solutions :
generate a XSD and the C# classes corresponding to this XSD : see [https://stackoverflow.com/questions/19359691/diff-between-top-1-1-and-select-1-in-sql-select-query/19359757#19359757],
directly define a table, instead of a string field