Im trying to deserialize an XML file with XmlSerializer, however im getting this exception:
"There is an error in XML document (1,
2)" The innerexception is:
"<Mymessage
xmlns='http://MyMessages/'> was not
expected."
Which is the very first line in the XML file. my guess is that it has something to do with the xmlns.
I tried to ask Google, and then tried to add the following line to my code
[XmlRoot("MyMessage", Namespace="'http://MyMessages/")]
But I still get the same exception.
In the constructor of the XmlSerializer i needed to specify a default namespace, after doing that everything worked just fine
Please provide the full XML file code to help understand the issue better.
Also put this as the first line in the xml file and see if this solves the issue
<?xml version="1.0" encoding="utf-8"?>
Further to CruelIO's response, I resolved the error by adding:
[XmlRoot("RenderResult", Namespace = "http://mynamespace.uri.org")]
to the class that I was trying to deserialize. e.g: the serialization code was:
RenderResult result;
using (var memoryStream = new MemoryStream(data))
{
var xmlSerializer = new XmlSerializer(typeof(RenderResult));
result = (RenderResult)xmlSerializer.Deserialize(memoryStream);
}
and my class looked like this:
[XmlRoot("RenderResult", Namespace = "http://mynamespace.uri.org")]
public class RenderResult
{
}
It sounds like you have a borked xml file. Easy ways to find out:
try loading it into an xml viewer
or just make sure it has a .xml extension and load in VS or IE
or run xsd.exe over it
If they complain, then the xml is certainly corrupt.
If they work fine, and display your data, then you probably have the serialization attributes wrong. Try using xsd.exe with the "/classes" switch to see what it would do with it...
Related
Accidently, I stumpled across a misformatted XML file having this content:
<?xml version="1.0" encoding="utf-8"?>
<MainModel xmlns:ctl="http://schemas.catelproject.com" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" ctl:graphid="1">
<DataId>123</DataId>
<DataName>Main Data Name</DataName>
<DataCollection ctl:graphid="2">
<SubModel ctl:graphid="3" xmlns:d0p0="http://schemas.datacontract.org/2004/07/CatelSpoiledDerialization.Models" i:type="d0p0:SubModel">
<SubId>200</
As the XML code shows, my example project (https://github.com/thoblerone/CatelSpoiledDerialization) is using the Catel framework, but deep debugging points towards a possible issue in System.Runtime.Serialization.XmlReader
The code to deserialize is pretty straght forward
var iXmlSer = SerializationFactory.GetXmlSerializer();
using var fileStream = File.Open(res.FileName, FileMode.Open);
var myData = iXmlSer.Deserialize<MainModel>(fileStream);
Yet, the call to Deserialize will never finish. Stepping through with the debugger, I see that the underlying .net XmlReader is calling MoveToContent while pointing to defective element (SubId) but the call will never succeed nor does it throw an exception, which I would gladly accept.
Am I missing come xml reader configuration that would check file conformity before tryinto to read the stuff?
I am trying to deserialize a file, none of the other solutions are working for me.
This is the code. I get the error on the 'customerList' line
using (StreamReader customerStreamReader =
new StreamReader(#"C:\...\ShoppingApplication\bin\Debug\Customer.xml"))
{
customerList = (List<Customer>)customerSerializer.Deserialize(customerStreamReader);
}
Look into using XDocument instead for it will be more robust in reporting errors, though the 0,0 location is a common one. Avoid using streams because they are so, .Net 2.
Here is an example:
var doc = XDocument.Load(#"C:\...\ShoppingApplication\bin\Debug\Customer.xml");
Console.WriteLine(doc);
Then extract what is needed from the actual nodes.
For anybody coming here from google:
If you do not want to use XDocument, then you must make sure that your .xml is NOT empty. Once I added something, I was able to deserialize it just fine. Hope this helps!
I started with three (3) XSD files provided from an external party (one XSD links to the other two). I used the xsd.exe tool to generate a .NET object by running the following command: xsd.exe mof-simpleTypes.xsd mof-isp.xsd esf-submission.xsd /c and it generated a single CS file with a handful of partial objects.
I've created an XmlSerializerNamespaces object and fill with the namespaces required (two directly used in the provided sample XML file as well as two others that don't appear to be referenced). I have successfully generated an XML file using the following method:
private XmlDocument ConvertEsfToXml(ESFSubmissionType type)
{
var xml = new XmlDocument();
var serializer = new XmlSerializer(type.GetType());
string result;
using (var writer = new Utf8StringWriter()) //override of StringWriter to force UTF-8
{
serializer.Serialize(writer, type, _namespaces); //_namespaces object holds all 4 namespaces
result = writer.ToString();
}
xml.LoadXml(result);
return xml;
}
My problem that I'm facing is in the generated CS file, one of the objects has a property (another generated partial object) that is of type XmlElement. I have successfully built the object in code, and I'm having an issue converting the object to an XmlElement. The questions and answers I have found here on SO say convert it to an XmlDocument first and then take the DocumentElement property. This works, however the returned XML has namespaces embedded in the element as follows:
<esf:ESFSubmission xmlns:isp="http://www.for.gov.bc.ca/schema/isp" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:esf="http://www.for.gov.bc.ca/schema/esf">
<esf:submissionMetadata>
<esf:emailAddress>test#test.com</esf:emailAddress>
<esf:telephoneNumber>1234567890</esf:telephoneNumber>
</esf:submissionMetadata>
<esf:submissionContent>
<isp:ISPSubmission xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:esf="http://www.for.gov.bc.ca/schema/esf" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:isp="http://www.for.gov.bc.ca/schema/isp">
<isp:ISPMillReport>
<isp:reportMonth>12</isp:reportMonth>
<isp:reportYear>2014</isp:reportYear>
<isp:reportComment>comment</isp:reportComment>
<isp:ISPLumberDetail>
<isp:species>FI</isp:species>
Note: this is just a partial of the generated XML file (for illustration purposes).
As you can see, each XML node is prefixed with the namespace variable. My question is: how can I do this in code? Is my approach sound and if so, then how do NOT include the namespaces in the ISPSubmission node OR if there is a better way to approach this problem that I overlooked, please provide insight. My desired outcome is to have all namespace definitions at the top of the document (their appropriate location) and not on the sub elements - as well as maintain the namespace variables on each element as illustrated above.
EDIT (after reggaeguitar's comment)
Here is the sample XML document I was provided
<?xml version="1.0" encoding="UTF-8"?>
<esf:ESFSubmission xmlns:esf="http://www.for.gov.bc.ca/schema/esf"
xmlns:isp="http://www.for.gov.bc.ca/schema/isp" xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.for.gov.bc.ca/schema/esf esf-submission.xsd
http://www.for.gov.bc.ca/schema/isp mof-isp.xsd">
<esf:submissionMetadata>
<esf:emailAddress>mailto:eric.murphy#cgi.com</esf:emailAddress>
<esf:telephoneNumber>6044445555</esf:telephoneNumber>
</esf:submissionMetadata>
<esf:submissionContent>
<isp:ISPSubmission>
<isp:ISPMillReport>
<isp:reportMonth>06</isp:reportMonth>
<isp:reportYear>2014</isp:reportYear>
<isp:reportComment>Up to 4000 characters is permitted for notes in this element.</isp:reportComment>
<isp:ISPLumberDetail>
<isp:species>FI</isp:species>
<isp:lumberGrade>EC</isp:lumberGrade>
<isp:gradeDescription/>
<isp:size>2x4</isp:size>
<isp:finishType/>
<isp:length>10</isp:length>
<isp:thickWidthUom>IN</isp:thickWidthUom>
<isp:volumeUnitOfMeasure>MBM</isp:volumeUnitOfMeasure>
<isp:volume>11543.987</isp:volume>
<isp:amount>1467893.98</isp:amount>
<isp:invoiceNumber>837261</isp:invoiceNumber>
</isp:ISPLumberDetail>
<isp:ISPLumberDetail>
<isp:species>CE</isp:species>
<isp:lumberGrade/>
<isp:gradeDescription/>
<isp:size/>
<isp:finishType>D</isp:finishType>
<isp:thickness>40</isp:thickness>
<isp:width>100</isp:width>
<isp:thickWidthUom>MM</isp:thickWidthUom>
<isp:volumeUnitOfMeasure>MBM</isp:volumeUnitOfMeasure>
<isp:volume>9743.987</isp:volume>
<isp:amount>1247893.98</isp:amount>
<isp:invoiceNumber/>
</isp:ISPLumberDetail>
<isp:ISPChipDetail>
<isp:species>CE</isp:species>
<isp:unitOfMeasure>BDT</isp:unitOfMeasure>
<isp:wholeLogInd>N</isp:wholeLogInd>
<isp:destinationCode>FBCO</isp:destinationCode>
<isp:destinationDescription/>
<isp:volume>563</isp:volume>
<isp:amount>54463</isp:amount>
<isp:invoiceNumber>12345679</isp:invoiceNumber>
</isp:ISPChipDetail>
</isp:ISPMillReport>
<isp:ISPSubmitter>
<isp:millNumber>103</isp:millNumber>
<isp:contactName>Dave Marotto</isp:contactName>
<isp:contactEmail>eric.murphy#cgi.com</isp:contactEmail>
<isp:contactPhone>2507775555</isp:contactPhone>
<isp:contactPhoneExtension>1234</isp:contactPhoneExtension>
</isp:ISPSubmitter>
</isp:ISPSubmission>
</esf:submissionContent>
</esf:ESFSubmission>
Solved my problem by doing the whole thing in code and not even using the xsd.exe to generate a .NET object.
So I'm writing a C# app that has a couple of XML files added as resources. I read from these XML files to populate objects in the code using XML serialization and it works perfectly. So I can access the files like so (I've left some code out, just have the important bits):
using TestApp.Properties;
XmlSerializer serializer = new XmlSerializer(typeof(MapTiles));
StringReader sr = new StringReader(Resources.Maps);
mapTiles = (MapTiles)serializer.Deserialize(sr);
Now however, I'd like to do the opposite. I'd like to take some data and write it to these XML resource files. However, I seem to be running into trouble with this aspect and was hoping someone could see something I'm messing up or let me know what I need to do? Here's what I'm trying to do:
XmlSerializer serializer = new XmlSerializer(typeof(MapTiles));
TextWriter writer = new StreamWriter(Resources.Maps);
serializer.Serialize(writer, tempGroup);
writer.Close();
When I run this code though, I get an error on the 2nd line that says ArgumentException was unhandled - Empty path name is not legal.
So if anyone has any thoughts I would greatly appreciate some tips. Thanks so much.
The exception is being raised because you are passing Resources.Maps into StreamWriter. StreamWriter is handling this as a string and assuming it is file path for the stream. But the file path is empty so it is throwing an exception.
To fix out the StreamWriter line you could specify a local temporary file instead of Resources.Maps or use StringWriter with the default constructor e.g. new StringWriter().
If you are writing .resx files then ResXResourceWriter is the class you need. It will also handle your stream writing too. See http://msdn.microsoft.com/en-us/library/system.resources.resxresourcewriter.aspx and http://msdn.microsoft.com/en-us/library/ekyft91f.aspx. The second page has examples on how to use the class but breifly you would call something like this:
XmlSerializer serializer = new XmlSerializer(typeof(MapTiles));
using (StringWriter stringWriter = new StringWriter())
{
serializer.Serialize(stringWriter, tempGroup);
using (ResXResourceWriter resourceWriter = new ResXResourceWriter("~/App_GlobalResources/some_file.resx"))
{
resourceWriter.AddResource("Maps", stringWriter.ToString());
}
}
If you want to write out an assembly that has a dynamically created resource in it the you can emit a new assembly. In that case have a look here http://msdn.microsoft.com/en-us/library/8ye65dh0.aspx.
The StreamWriter constructor is throwing the exception because Resources.Maps is an empty string.
Check out the documentation on MSDN:
http://msdn.microsoft.com/en-us/library/fysy0a4b.aspx
Hmm, after trying some other things and doing even more research it appears that the problem is that you cannot write to a resource that is part of the application. Something to do with the resource being written into the assembly and therefore it's not writable. So I'll have to modify my approach and write the output to a different file.
Unless of course anyone does know differently. This is just what I've discovered so far. Thanks to those who had some ideas though, much appreciated.
I have a rather detailed xml file. Below is the top level nodes (I have included the ellipse as the lower level nodes are all well formed and properly filled with data):
<?xml version="1.0" encoding="UTF-8"?>
<config>
<Models>...</Models>
<Data>...</Data>
</config>
I have created an xsd file from using the Visual Studio 2008 command prompt:
xsd sample.xml
This generates the xsd file just fine. I then auto generate classes from the xsd with the command:
xsd sample.xsd /classes
For the deserialization of the xml file into a class object, I'm using the read function in the helper class:
public class XmlSerializerHelper<T>
{
public Type _type;
public XmlSerializerHelper()
{
_type = typeof(T);
}
public void Save(string path, object obj)
{
using (TextWriter textWriter = new StreamWriter(path))
{
XmlSerializer serializer = new XmlSerializer(_type);
serializer.Serialize(textWriter, obj);
}
}
public T Read(string path)
{
T result;
using (TextReader textReader = new StreamReader(path))
{
XmlSerializer deserializer = new XmlSerializer(_type);
result = (T)deserializer.Deserialize(textReader);
}
return result;
}
}
When attempting the deserialization with:
var helper = new XmlSerializerHelper<configModels>();
var obj = new configModels();
obj = helper.Read(filepath);
I receive an error that I have deduced is because the deserializer is looking for the 'Models' node but the corresponding class name was generated as a combination of the root node and the 'Model' node (configModels). Why are the class names generated like this?
I tried to deserialize from the top node using:
var helper = new XmlSerializerHelper<config>();
var obj = new config();
obj = helper.Read(filepath);
Unfortunately, this the results in a slew of errors like the following:
System.InvalidOperationException was unhandled by user code
Message="Unable to generate a temporary class (result=1).
error CS0030: Cannot convert type 'Application.Lease[]' to 'Application.Lease'
error CS0030: Cannot convert type 'Application.CashFlow[]' to 'Application.CashFlow'
...ect.
Can somebody steer me towards what I might be doing wrong with my xsd auto-generating?
XSD.EXE is a good start - but it's far from perfect. Also, based on the XML you provided, XSD.EXE can't always decide for sure whether something is a single instance of an object, or an open-ended array of objects.
This seems to be the case for your two elements - Application.Lease and Application.CashFlow. How are they defined in the generated XSD file? Does that make sense to you? Quite possibly, you'd have to add a little hints, such as:
<xs:element name="Lease" minOccurs="0" maxOccurs="1" />
for an optional property, that's zero or one occurences only. Things like that are really hard for the xsd.exe tool to figure out based on just a single XML sample file.
Marc
Go to your generated class and change all from [][] ---> []
There's an issue with xsd.exe and lists. You have to go into the generated class and manually edit the file to the correct type. I've switched to using Xsd2Code. So far it doesn't seem to have this problem.
Another issue that can cause this problem is that the xml file contents between the tags (meaning the content) is still encoded when it shouldn't be. For example, the <br> tags in my content were still <br> instead of <br />. The xsd generator turned these into elements in the schema then mislabeled them as unbounded since there was more than one found. Unencoding them fixed the problem and generated the classes correctly.