<Fruits>
<FruitName>Amla</FruitName>
<FruitPrice>10 US DOLLARS</FruitPrice>
<Origin>
<Country>INDIA</Country>
<NativeName>GOOSEBERRY</NativeName>
<Availability>PLENTY</Availability>
</Origin>
<OtherInfo>
<FiberPercentage>1.11</FiberPercentage>
<MagnesiumPercentage>0.02</MagnesiumPercentage>
</OtherInfo>
While De serializing the above XML structure, I use something like,
Xml
XmlElement("FruitsList")]
public List<Fruits> FruitsImport { get; set; }
In Fruits Class, I have something like:
[XmlAnyElement]
public List<XmlElement> FruitElements { get; set; }
[XmlElement("Origin")]
public List<XmlElement> FruitOrigin { get; set; }
[XmlElement("OtherInfo")]
public List<XmlElement> OtherInfo { get; set; }
FruitElement retrieves the FruitName and FruitPrice.
FruitOrigin retrives Country Info alone.
OtherInfo retrives FiberPercentage alone.
Any ideas on how to get all the info under <Origin> and <OtherInfo> tags ?
Because you have elements nested in both <origin> and <otherinfo> tags, you need to define a class for them as well when performing deserialization.
[XmlElement("Origin")]
public List<Origins> FruitOrigin { get; set; }
You would define the origin class the same way as you did for fruit class.
(The skeleton of Origin class would be something as below:
[Serializable]
public class Origin
{
[XmlAnyElement]
public List<XmlElement> OriginElements { get; set; }
}
)
The best way is to write XSD schema for the XML and generate class from XSD schema using XSD.exe, this way you can validate that always XML and class matches to XSD and never have issue with Serialization/ Deserialization.
You can create batch file like below to generate class from xsd schema:
del Configuration.AutoGenerated.cs
"%ProgramFiles%\Microsoft SDKs\Windows\v6.0A\bin\xsd" Test.Configuration.xsd /c /n:Test.Configuration
rename Test_Configuration.cs Configuration.AutoGenerated.cs
pause
You can see more usage examples at above link for XSD.exe.
It will generate partial classes so you can easily extend it further if required.
Related
Hi I have the xml format defined for which i need to serialize from my object.
My XML will look like :
<PerfCheckConsidered>
<PerfMarker PercentageIncrease="21.4171662006946" MaxValue="6650.55" MinValue="5477.438" TS_09082021093913="5961.733" TS_09082021093646="6650.55" TS_09082021093358="5477.438" TS_09082021093136="5510.135" TS_09082021092614="5768.742" PerfMarkerName="Marker1"/>
<PerfMarker PercentageIncrease="20.9911157408996" MaxValue="7371.881" MinValue="6092.911" TS_09082021093913="7371.881" TS_09082021093646="6092.911" TS_09082021093358="6345.139" TS_09082021093136="6289.624" TS_09082021092614="6782.205" PerfMarkerName="Marker1"/>
<PerfMarker PercentageIncrease="9.22930544021455" MaxValue="6183.199" MinValue="5660.751" TS_09082021093913="6183.199" TS_09082021093646="5660.751" TS_09082021093358="6000.608" TS_09082021093136="5951.08" TS_09082021092614="5870.288" PerfMarkerName="Marker1"/>
<PerfMarker PercentageIncrease="25.0711884164738" MaxValue="10075.0518" MinValue="8055.4538" TS_09082021093913="10062.1176" TS_09082021093646="10061.7749" TS_09082021093358="10075.0518" TS_09082021093136="8055.4538" TS_09082021092614="10063.9758" PerfMarkerName="Marker2"/>
<PerfMarker PercentageIncrease="13.2855819181415" MaxValue="8250.0617" MinValue="7282.5346" TS_09082021093913="8237.9737" TS_09082021093646="8245.9522" TS_09082021093358="8240.958" TS_09082021093136="8250.0617" TS_09082021092614="7282.5346" PerfMarkerName="Marker2"/>
<PerfMarker PercentageIncrease="29.7888969731873" MaxValue="50.4823" MinValue="38.8957" TS_09082021093913="50.4823" TS_09082021093646="46.8748" TS_09082021093358="38.8959" TS_09082021093136="38.8957" TS_09082021092614="40.8915" PerfMarkerName="Marker3"/>
<PerfMarker PercentageIncrease="54.5326940955576" MaxValue="16.9544" MinValue="10.9714" TS_09082021093913="11.9676" TS_09082021093646="12.9662" TS_09082021093358="16.9544" TS_09082021093136="10.9714" TS_09082021092614="10.9714" PerfMarkerName="Marker3"/>
<PerfMarker PercentageIncrease="14.028196761682" MaxValue="64.8256" MinValue="56.8505" TS_09082021093913="60.8377" TS_09082021093646="62.8326" TS_09082021093358="56.8505" TS_09082021093136="59.2591" TS_09082021092614="64.8256" PerfMarkerName="Marker3"/>
<PerfMarker PercentageIncrease="8.33604893089013" MaxValue="25.9311" MinValue="23.9358" TS_09082021093913="25.9311" TS_09082021093646="23.9358" TS_09082021093358="25.93" TS_09082021093136="25.9306" TS_09082021092614="24.9344" PerfMarkerName="Marker3"/>
</PerfCheckConsidered>
Here in above XML, TagName like TS_09082021093913,TS_09082021093646,TS_09082021093136,TS_09082021092614 are not known in compile time, These are TimeStamp Names formed from files names present in local disk.
How should i define my object structure to fill data of this kind
Current class looks like (From this structure i cannot get the desired xml format)
public class PerfCheck
{
public string PerfMarkerName { get; set; }
public string PercentageIncrease { get; set; }
public string MaxValue { get; set; }
public string MinValue { get; set; }
public string Marker { get; set; }
public List<TimeStampToInstances> TimeStampToMarkerValues { get; set;
}
[Serializable]
public class TimeStampToInstances
{
public string TimeStamp { get; set; }
public List<double> InstancesValues { get; set; }
}
Currently i am using my Custom logic to form the XML, But i am told to use normal xml serialization and try to modify the class structure to accommodate xml format
Is this possible ?
Thanks all for your valuable inputs.
I was able to achieve required XML format by using dynamic object.
I Serialized my dynamic object to intermediate XML, From which i created my XML in required format.
I have the class
public class TestModel
{
public int Number { get; set; }
public string Text { get; set; }
}
which is converted with the following xml
<TestModel>
<Number>2</Number>
<Text>text</Text>
</TestModel>
But i need to wrap this with multiples xml tags
<Wrapper1>
<Wrapper2>
<TestModel>
<Number>2</Number>
<Text>text</Text>
</TestModel>
</Wrapper2>
</Wrapper1>
Is there any attribute to be able to put this type of wrappers? Like
[XElementWrapper("Wrapper1", "Wrapper2")]
public class TestModel
{
..
}
I dont want to create dummy classes only to contains the wrappers or create the xml element by code
Yes, you can make it by implementing IXmlSerializable
I am attempting to reproduce a XML file structure programmatically using c#. The file structure is giving me difficulties in that it makes use of a tag as an empty data set or a parent tag for child elements under nodes. As an example:
<?xml version="1.0" encoding="UTF-8"?>
<A>
<B>
<C>
<E></E>
<E></E>
<F>false</F>
<F>true</F>
<F>false</F>
<G>
<H/>
</G>
</C>
<B>
<D>
<E>continue</E>
<G>
<F>false</F>
<E>1</E>
</G>
</D>
<B/>
<D>
<E></E>
</D>
<B/>
</B>
</B>
</A>
The specific nodes giving me difficulty are the <B> nodes. I'm not sure how to structure the class so that it can contain a list of node elements in addition to itself which may or may not have values and have that be serialized into an XML document. Any help would be welcome, it may be complicated to explain so I am happy to elaborate.
If we were to make a schema for your <B> node, it would consist of a sequence of choice nodes, where an element of type <C>, <D>, or <B> itself might be chosen.
If we were to model this in c#, the natural way to do so would be to use a list of polymorphic objects, the items of which would correspond to the three element types. Luckily, as explained in this answer to Using XmlSerializer to serialize derived classes by Marc Gravell, this scenario is supported by XmlSerializer by annotating the polymorphic collection with [XmlElement(String, Type)] attributes, one for each concrete type that might appear in the collection.
Thus, you can define your data model as follows:
public class BaseNode
{
}
public class B : BaseNode
{
[XmlElement("B", typeof(B))]
[XmlElement("C", typeof(C))]
[XmlElement("D", typeof(D))]
public List<BaseNode> Nodes { get; } = new List<BaseNode>();
}
public class C : BaseNode
{
[XmlElement(ElementName="E")]
public List<string> E { get; set; }
[XmlElement(ElementName="F")]
public List<bool> F { get; set; }
[XmlElement(ElementName="G")]
public G1 G { get; set; }
}
public class D : BaseNode
{
[XmlElement(ElementName="E")]
public string E { get; set; }
[XmlElement(ElementName="G")]
public G2 G { get; set; }
}
public class G1
{
public string H { get; set; }
}
public class G2
{
public string F { get; set; }
public string E { get; set; }
}
[XmlRoot("A")]
public class A
{
public B B { get; set; }
}
Notes:
I made the 3 types that can appear in the B.Nodes collection inherit from a common ancestor BaseNode, so that it is not possible to add irrelevant items into the collection at runtime. If you don't want this, you could eliminate BaseNode and declare your collection as a List<object>.
It is my experience that the various tools mentioned in Generate C# class from XML do not always generate optimal c# classes from XML that has complex <xsd:choice> + <xsd:sequence> scenarios.
If you had a proper XSD, however, the tools from How to generate .NET 4.0 classes from xsd? would generate correct c# classes.
In your example you have two nodes named <G> that appear to have different schemas, so I had to create two types G1 and G2.
Demo fiddle here.
I'm parsing JSON data return by a third party.
I have my class generated with JSON2CSharp which works for the first sample we received. I tweaked it to have some JsonProperty settings so that it doesn't require certain properties that are not always present.
Now I received more samples and one of the datablobs changed format
from needing
public Translations Translations { get; set; }
to
public List<Translations> Translations { get; set; }
The blob however is information we do not need, for both performance and not having to deal with that and other pieces of information we do not need changing format, it would be ideal to just ignore it when deserializing it.
Now the real question is, should "JsonIgnore" just ignore the entire blob of data irregardless if it is in a different format then defined in the class? Or do I have to program around that?
So if I do
[JsonIgnore]
public string Translations { get; set; }
will it also ignore Translations when it gets sent a list or an object?
Can I use the same syntax with JsonIgnore as I can with JsonProperty and just say
[JsonIgnore(PropertyName = "translations")]
or does JsonIgnore just toss out anything it receives?
Additionally question:
Is it convention that when there are no translations, I get:
"translations":[]
and when there are translations I get:
"translations":{"CA":"blabla","DD":"C : blablah"}
Or is this likely a bug in the third party's website?
ADDED:
1: The Translations can switch between string, list and object between every fetch of the JSON.
2: For using DataMembers ignoring everything I don't actually need, in a class with subclasses, do I have to tell it that the subclass is [DataMember] or the subclasses properties are [DataMember]?
I would explicitly specify exactly the properties I wanted serialized/deserialized in my data class using DataContractAttribute and DataMemberAttributes for the members you actually want to deserialize.
This is opt in, so no attempt is made to shoehorn anything extra in your JSON into your data class, and anything extra in your data class doesn't show up in serialized JSON.
So assuming your class right now looks like this:
class MyData {
// Old member
// public Translations Translations { get; set; }
public List<Translation> Translations { get; set; }
public string ThisShouldBeSerialized { get; set; }
}
You can change it so things that you want serialized are explicitly marked as such, and anything not marked for serialization is ignored by default:
[DataContract]
class MyData {
// Old member
// public Translations Translations { get; set; }
public List<Translation> Translations { get; set; }
[DataMember]
public string ThisShouldBeSerialized { get; set; }
}
And then:
var myJSON = #"{
'ThisShouldBeSerialized': 'test',
'Translations': {
'Some' : 'Strange',
'Data' : 'Blob'
}
}";
var result = JsonConvert.DeserializeObject<MyData>(myJSON);
I've got a problem when deserializing partially works. When I have an xml node with attributes, all the attribute values get loaded correctly into my class but when I use elements, it just returns null.
I have the following stored in an xml file:
<?xml version="1.0" encoding="utf-8"?>
<email>
<from>admin#company.com</from>
<recipients>
<recipient>user1#company.com</recipient>
<recipient>user2#company.com</recipient>
</recipients>
<subject>Test subject</subject>
<body>Test body</body>
<attachments>
<attachment>c:\test.txt</attachment>
<attachment>c:\test1.txt</attachment>
<attachment>c:\test2.txt</attachment>
</attachments>
</email>
My main class is defined as follows:
[Serializable]
[XmlRoot("email")]
public class EmailNotification
{
[XmlElement("from")]
public string From { get; set; }
[XmlElement("subject")]
public string Subject { get; set; }
[XmlElement("body")]
public string Body { get; set; }
[XmlArray("recipients")]
[XmlArrayItem("recipient")]
public List<EmailNotificationRecipient> Recipients { get; set; }
[XmlArray("attachments")]
[XmlArrayItem("attachment")]
public List<EmailNotificationAttachment> Attachments { get; set; }
public EmailNotification()
{
this.Attachments = new List<EmailNotificationAttachment>();
this.Recipients = new List<EmailNotificationRecipient>();
}
}
Here is my recipient class:
[Serializable]
public class EmailNotificationRecipient
{
public EmailNotificationRecipient()
{
}
[XmlElement("recipient")]
public string Recipient { get; set; }
}
I'm not going to bother displaying the attachment class as it is identical in regards to its definition as the recipient class.
All the simple elements are being filled correctly and my array is being build but all the elements are null inside it.
When debugging, I can see that my arrays have 2 items for the recipients and 3 items for the attachments but when I check the value inside, each of the array item are null.
I've also added a constructor the EmailNotificationRecipient class and set a breakpoint on it and it hits my breakpoint every time for each defined recipient.
With the above 2 points, it would make you believe that everything is ok with my class definitions or it would not manage to find the correct number of elements but as mentioned, all objects within my array are set to null even though the correct number of objects are created.
Originally I had the XmlArrayItem defined with the type:
[XmlArrayItem("recipient", typeof(EmailNotificationRecipient))]
public List<EmailNotificationRecipient> Recipients { get; set; }
I removed it to see if it would make any difference, but to no avail.
What am I missing? This is driving my bonkers!!!
Thanks.
UPDATE
See answer below from #NoIdeaForName.
The way I currently have it defined would have meant that in order for it to return a value, my xml should have looked like:
<recipients>
<recipient><recipient></recipient></recipient>
</recipients>
as my array is expecting a class recipient when in fact all I have within each recipient node is a string, so the array should have been defined as follows:
[XmlArray("recipients")]
[XmlArrayItem("recipient")]
public List<string> Recipients { get; set; }
Now on the other hand, if each of my recipients in my xml were defined like this:
<recipients>
<recipient>
<fname><fname>
<lname><lname>
</recipient>
</recipients>
then it would make sense to define a separate class the way I had it i.e. EmailNoticiationRecipient, but instead of having recipient as a property, you would have fname and lname.
Thanks again #NoIdeaForName :)
as you said you are doing
[XmlArray("attachments")]
[XmlArrayItem("attachment")]
public List<EmailNotificationAttachment> Attachments { get; set; }
in the EmailNotification class and your Attachments class is
[Serializable]
public class EmailNotificationRecipient
{
public EmailNotificationRecipient()
{
}
[XmlElement("recipient")]
public string Recipient { get; set; }
}
that means your xml should look like:
<recipients>
<recipient><recipient>user1#company.com</recipient></recipient>
<recipient><recipient>user2#company.com</recipient></recipient>
</recipients>
because in every recipient tag there is a class and in every recipient class should be a property name(tag as) recipient
the best way to check it would be to create a class with values and serialize them and see how the output looks like