I'm a bit out of my element. I've used xsd.exe to create an xsd schema from an xml file, and then to create a C# class from that xsd. That all seems to work fine.
At the moment I'm just trying to get the XML deserialized. The file I'm deserializing if the very same file I used to build the class originally. Here's my code:
String xsdPath=#"C:\Users\tol56881\Documents\dnd4e.xsd";
String xmlPath=#"C:\Users\tol56881\Documents\dnd4e.xml";
String xsdNamespace="";
//Validation stuff
XmlParserContext context = new XmlParserContext(null, null, "", XmlSpace.None);
XmlValidatingReader vr = new XmlValidatingReader(xmlPath, XmlNodeType.Element, context);
vr.ValidationType = ValidationType.Schema;
vr.Schemas.Add(xsdNamespace, xsdPath);
while (vr.Read()) ;
//Actually reading the file
TextReader tr = new StreamReader(xmlPath);
D20Character character = (D20Character)(new XmlSerializer(typeof(D20Character))).Deserialize(tr);
It compile fine, but when I try to run it I get the an error that's repeated for four different objects. I've given an example below, changing the names of the objects.
Unable to generate a temporary class (result=1).
error CS0030: Cannot convert type 'Namespace.ObjectName[]' to 'Namespace.ObjectName'
error CS0029: Cannot implicitly convert type 'Namespace.ObjectName' to 'Namespace.ObjectName[]'
So it seems like the program is trying to go from array to object and back to array, but I'm not really sure. The auto-generated class code is a huge mess that's difficult to wade through. I'm hoping that maybe there's something simple I'm missing here.
Thanks!
I managed to fix this. Each of the four objects in question were generated as doubly-indexed arrays, such as:
private loot[][] lootTallyField;
and
public loot[][] LootTally
{
get
{
return this.lootTallyField;
}
set
{
this.lootTallyField = value;
}
}
All I did was remove one set of brackets, and it all seems to be working fine. No problems with deserialization and a quick inspection of the deserialized object makes it look like the data was loaded correctly.
private loot[] lootTallyField;
and
public loot[] LootTally
{
get
{
return this.lootTallyField;
}
set
{
this.lootTallyField = value;
}
}
Still not sure why xsd.exe made these doubly-indexed if they're not supposed to be. I feel like I'm still missing something, hence why this question is still open.
Particularly, if I ever need to re-generate this code, then I'd need to reapply the fix, which kind of defeats the purpose of using a partial class in the first place...
There is a problem on xsd.exe tool, I will try to explain.
If you have a complexType with a sequence inside that has a child complexType with a sequence and the first one does not have any other elements / attributes, then the generated class will have only 1 generated type, instead of 2 and it will be a double array.
If you make the double array into a single array, you will be able to deserialize your xml just fine.
HOWEVER this will produce the following unexpected result.
If your xml looks like the below.
<root>
<loot>
<tally>value1</tally>
<tally>value2</tally>
</loot>
<loot>
<tally>value3</tally>
<tally>value4</tally>
</loot>
</root>
Then your deserialized object, in the lootTally array would only contain the value3 and value4 items instead of having all 4.
So you have 2 options to fix this correctly:
Alter the xsd file by adding a dummy in the first sequence, and run xsd.exe again, so that when it generates the class it will not create a double array, and then you can delete the dummy attribute from the class.
Alter the generated class, add a new class named loot which will contain an array of tally objects which you already have (and only need to alter the name).
Please note that in option 2 you may have to change some declarations if you have an XmlArrayItemAttribute to XmlElementAttribute.
Hope this helps
Related
At the moment, I'm trying to figure out how to save a Jint.NET JavaScript environment to file, so I can load it again later.
However, I'm having major trouble trying to serialize/deserialize the Jint.Native.JsValue class. Since it has no constructor, Newtonsoft doesn't like deserializing to it, and when serializing, it ignores all private properties, resulting in only the Type field being saved.
string saved = JsonConvert.SerializeObject(someJsValue); //output: {Type: x}
JsonConvert.DeserializeObject<JsValue>(saved); //error: no constructor
Is there any way around this so I can load/save this properly?
When I deserialize an XML document with XmlTextReader, a textual element for which there is no corresponding class is simply ignored.
Note: this is not about elements missing from the XML, which one requires to be present, but rather being present in the XML text, while not having an equivalent property in code.
I would have expected to get an exception because if the respective element is missing from the runtime data and I serialize it later, the resulting XML document will be different from the original one. So it's not safe to ignore it (in my real-world case I have just forgotten to define one of the 99+ classes the given document contains, and I didn't notice at first).
So is this normal and if yes, why? Can I somehow request that I want to get exceptions if elements cannot be serialized?
In the following example-XML I have purposely misspelled "MyComandElement" to illustrate the core problem:
<MyRootElement>
<MyComandElement/>
</MyRootElement>
MyRootElement.cs:
public class CommandElement {};
public class MyRootElement
{
public CommandElement MyCommandElement {get; set;}
}
Deserialization:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyRootElement));
XmlTextReader xmlReader = new XmlTextReader(#"pgtest.xml");
MyRootElement mbs2 = (MyRootElement)xmlSerializer.Deserialize(xmlReader);
xmlReader.Close();
As I have found out by accident during further research, this problem is actually ridiculously easy to solve because...
...XmlSerializer supports events! All one has to do is to define an event handler for missing elements
void Serializer_UnknownElement(object sender, XmlElementEventArgs e)
{
throw new Exception("Unknown element "+e.Element.Name+" found in "
+e.ObjectBeingDeserialized.ToString()+" in line "
+e.LineNumber+" at position "+e.LinePosition);
}
and register the event with XmlSerializer:
xmlSerializer.UnknownElement += Serializer_UnknownElement;
The topic is treated at MSDN, where one also learns that
By default, after calling the Deserialize method, the XmlSerializer ignores XML attributes of unknown types.
Not surprisingly, there are also events for missing attributes, nodes and objects.
So is this normal and if yes, why?
Because maybe you're consuming someone else's XML document and whilst they define 300 different elements within their XML, you only care about two. Should you be forced to create classes for all of their elements and deserialize all of them just to be able to access the two you care about?
Or perhaps you're working with a system that is going to be in flux over time. You're writing code that consumes today's XML and if new elements/attributes are introduced later, they shouldn't stop your tested and deployed code from being able to continue to consume those parts of the XML that they do understand (Insert caveat here that, hopefully, if you're in such a situation, you/the XML author don't introduce elements later which it is critical to understand to cope with the document correctly).
These are two sides of the same coin of why it can be desirable for the system not to blow up if it encounters unexpected parts within the XML document it's being asked to deserialize.
Hi I'm quite new to C# and I'm trying to make a text editor that saves and loads Plaintext formats. I've used NewtonSoft.Json NuGet package, but I'm getting an error. I've stated a string called textToLoad, which is set to a JsonConvert.DeserializeObject. Only thing is, it says it can't convert an object to a string! I tried toString(); but it still had the same error.
It is kind of hard without the code. The process of serializing and deserializing is pretty straight forward using Json.Net. So this is an example from their documentation:
YourType yourObject= new YourType();
yourObject.Property="something";
string output = JsonConvert.SerializeObject(yourObject);
//For some reason you want this to be string, but is the type you serialized in the first place
YourType textToLoad= JsonConvert.DeserializeObject<YourType>(output);
This outlines the basic works of serializing and deserializing. But we don't really know the details of your implementation.
Hope it helps.
You can't deserialize into a string like that. At simplest form you started with JSON in the form of:
{ value: "someString" }
If you want something out of it, you must deserialize and then get the value from it.
dynamic foo = JsonConvert.DeserializeObject<dynamic>(theJson);
var textToLoad = foo.value.ToString();
You must deserialize to something in order to inspect and get properties from it.
[Edit] - Perhaps I'm not understanding. But if you share code, I'll update my answer.
I use the XML format to keep settings for my C# project.
Theses XMLs are deserialized into C# classes.
Often enough, a class design changes but I forget to update the XML. Deserialization usually works fine and missing elements just get their default values.
This behavior is not desirable for me. I would like to have automatic validation that asserts the class and the XML have exactly the same structure.
I know I can create XML schemas (e.g using XSD) for my classes, but I could not figure an easy way to do it automatically and not manually (recall my classes' design changes often). Also, this solution seems kind of unnatural. I do not really need XML schemas. I have classes and their serialized XML instances. Adding schemas seems superfluous.
Thanks a bunch.
Why you don't create a method in your settings class that can be invoked after xml deserialization?
Suppose you have a class like this:
class Settings {
public string Property1 { get; set; }
public int Property2 { get; set; }
public bool IsValid() {
if(string.IsNullOrEmpty(Property1)) return false;
if(Property2 == 0) return false;
}
}
Using IsValid you can check everything in your class. Please, remember that this is an example. I think is good to manage object validation. If you change something in the time, you can edit the validation method to check new situations.
To go with Roberto's idea and take it a step further you could get all the properties via reflection:
var props = yourClass.GetType().GetProperties()
Inside of your validation function you could loop over those properties with:
foreach(var prop in props) // or foreach(var prop in yourClass.GetType().GetProperties())
{
//...Validation of property
}
If one of the properties has its standard-value you throw a custom exception that tells you you did not update your XML-file properly.
You can implement this using Version Tolerant Serialization (VTS) https://msdn.microsoft.com/en-us/library/ms229752%28v=vs.110%29.aspx
The Serialization Callbacks is what you are looking for in the VTS capabilities
I have a XML file, with a structure like
<items>
<item>
<someDetail>
A value here
</someDetail>
</item>
<item>
<someDetail>
Another value here
</someDetail>
</item>
</items>
With multiple items in it.
I want to deserialize the XML on session start ideally, to turn the XML data to objects based on a class (c# asp.net 4)
I have tried several ways with either no success, or a solution which seems clunky and inelegant.
What would people suggest?
I have tried using the xsd.exe tool, and have tried with the xml reader class, as well as usin XElement class to loop through the xml and then create new someObject(props).
These maybe the best and/or only way, but with it being so easy for database sources using the entities framework, I wondered if there was a similar way to do the same but from a xml source.
The best way to deserialize XML it to create a class that corresponds to the XML structure into which the XML data will deserialize.
The latest serialization technology uses Data Contracts and the DataContractSerializer.
You decorate the class I mentioned above with DataMember and DataItem attributes and user the serializer to deserialize.
I'd use directly the .NET XML serialization - classes declarations:
public class Item {
[XmlElement("someDetail")]
public string SomeDetail;
} // class Item
[XmlRoot("items")]
public class MyData {
[XmlElement("item")]
public List<Item> Items;
public static MyData Deserialize(Stream source)
{
XmlSerializer serializer = new XmlSerializer(typeof(MyData));
return serializer.Deserialize(source) as MyData;
} // Deserialize
} // class MyData
and then to read the XML:
using (FileStream fs = new FileStream(#"c:\temp\items.xml", FileMode.Open, FileAccess.Read)) {
MyData myData = MyData.Deserialize(fs);
}
I've concluded is there is not simple unified mechanism (probably due to the inherent complexities involved with non trivial cases - this question always crops up in the context of simple scenarios like your example xml).
Xml serialization is pretty easy to use. For your example, you would just have to create a class to contain a items and another class for the actual item. You might have to apply some attributes to get everything to work correctly, but the coding will not be much. Then it's as easy as -
var serializer = new XmlSerializer(typeof(ItemsContainer));
var items = serializer.Deserialize(...) as ItemsContainer;
Datasets are sometimes considered "yesterday tech" but I use them when they solve the problem well, and you can leverage the designer. The generated code is not pretty but the bottom line is you can persist to a database via the auto generated adapters and to XML using a method right on the data set. You can read it in this way as well.
XSD.exe isn't that bad once you get used to it. I printed the help to a text file and included it in my solutions for a while. When you use the /c option to create classes, you get clean code that can be used with the XmlSerialzier.
Visual Studio 2010 (maybe other versions too) has an XML menu which appears when you have an Xml file open and from that you can also generate an XSD from sample Xml. So in a couple of steps you could take your example xml and generate the XSD, then run it through XSD.exe and use the generated classes with a couple of lines XmlSerializer code... it feels like a lot of machinations but you get used to it.