472,954 Members | 2,376 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,954 software developers and data experts.

XmlSerializer - XmlTextReader vs. XmlNodeReader

I've run across a strange behaviour with XmlSerializer that I'm unable to explain. I came across this while trying to use XmlSerializer to deserialize from a the details of a SoapException. This should have worked fine since the class in question was already being serialized and deserialized as part of a Web service interface. What I found was that by deserializing from an XmlNodeReader instead of an XmlTextReader, XML Serialization doesn't work the same way as when it deserialized from an XmlTextReader.

This is easily reproduced with the following C# code:

using System;
using System.Xml;
using System.Xml.Serialization;
using System.Collections;

public class MyClass
{
public ArrayList Values = new ArrayList();
}

class Class1
{
[STAThread]
static void Main(string[] args)
{
MyClass myClass1 = new MyClass();
myClass1.Values.Add(123);
myClass1.Values.Add("abc");

XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
XmlWriter writer = new XmlTextWriter("temp.xml", System.Text.Encoding.UTF8);
serializer.Serialize(writer, myClass1);
writer.Close();

// Deserializing using an XmlTextReader works fine
MyClass myClass2 = (MyClass)serializer.Deserialize(new XmlTextReader("temp.xml"));
foreach (object value in myClass2.Values) Console.WriteLine(value.ToString());
Console.ReadLine();

// Deserializing using an XmlNodeReader over the same document doesn't work
XmlDocument doc = new XmlDocument();
doc.Load("temp.xml");
MyClass myClass3 = (MyClass)serializer.Deserialize(new XmlNodeReader(doc));
foreach (object value in myClass3.Values) Console.WriteLine(value.ToString());
Console.ReadLine();
}
}

The "temp.xml" file will contain the following:

<?xml version="1.0" encoding="utf-8"?>
<MyClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Values>
<anyType xsi:type="xsd:int">123</anyType>
<anyType xsi:type="xsd:string">abc</anyType>
</Values>
</MyClass>

The output will be:

123
abc

System.Xml.XmlNode[]
System.Xml.XmlNode[]

It would seem to me that this has got to be a bug since the XML infoset that XmlSerializer is consuming should be identical whether it is coming from an XmlTextReader or XmlNodeReader.

There is an obvious workaround (serialize the XmlNode to a MemoryStream, then deserialize from it using an XmlTextReader). Somehow writing then re-parsing the XML that has already been loaded into a DOM seems very ugly and unncessary. Can someone suggest an alternative solution, or an explanation for this behaviour?

Andy
Nov 12 '05 #1
4 11281
The problem is you are de-serializing into an ArrayList, and you haven't provided any hints to the serializer as to the types of the items in that list.
At De-serialization time, the runtime doesn't know what to de-serialize the various xml nodes into. When you de-serialize from a XmlTextReader, the serializer uses the xsi:type as guesses. When you de-serialize from an XmlNodeReader, you get (surprise!) XmlNodes, which correspond to the attributes and InnerText in that node.

To address this you could simply add some hints to the ArrayList Values. Eg:

public class MyClass
{
[XmlArray("Values")]
[XmlArrayItem("StringValue",typeof(System.String))]
[XmlArrayItem("IntValue",typeof(System.Int32))]

public ArrayList Values = new ArrayList();
}
Doing this you will get the same results using either Reader. If you have objects of completely arbitrary type in the arraylist, then you will want to add an
[XmlArrayItem("Unknown",typeof(System.Object))]

to the list of attributes. This will revert to the behavior of getting an XmlNode[] for that particular arraylist item.

-Dino
"Andy Neilson" <aneilsonNoSpam69AthotmailDotcom> wrote in message news:%2******************@TK2MSFTNGP09.phx.gbl...
I've run across a strange behaviour with XmlSerializer that I'm unable to explain. I came across this while trying to use XmlSerializer to deserialize from a the details of a SoapException. This should have worked fine since the class in question was already being serialized and deserialized as part of a Web service interface. What I found was that by deserializing from an XmlNodeReader instead of an XmlTextReader, XML Serialization doesn't work the same way as when it deserialized from an XmlTextReader.

This is easily reproduced with the following C# code:

using System;
using System.Xml;
using System.Xml.Serialization;
using System.Collections;

public class MyClass
{
public ArrayList Values = new ArrayList();
}

class Class1
{
[STAThread]
static void Main(string[] args)
{
MyClass myClass1 = new MyClass();
myClass1.Values.Add(123);
myClass1.Values.Add("abc");

XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
XmlWriter writer = new XmlTextWriter("temp.xml", System.Text.Encoding.UTF8);
serializer.Serialize(writer, myClass1);
writer.Close();

// Deserializing using an XmlTextReader works fine
MyClass myClass2 = (MyClass)serializer.Deserialize(new XmlTextReader("temp.xml"));
foreach (object value in myClass2.Values) Console.WriteLine(value.ToString());
Console.ReadLine();

// Deserializing using an XmlNodeReader over the same document doesn't work
XmlDocument doc = new XmlDocument();
doc.Load("temp.xml");
MyClass myClass3 = (MyClass)serializer.Deserialize(new XmlNodeReader(doc));
foreach (object value in myClass3.Values) Console.WriteLine(value.ToString());
Console.ReadLine();
}
}

The "temp.xml" file will contain the following:

<?xml version="1.0" encoding="utf-8"?>
<MyClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Values>
<anyType xsi:type="xsd:int">123</anyType>
<anyType xsi:type="xsd:string">abc</anyType>
</Values>
</MyClass>

The output will be:

123
abc

System.Xml.XmlNode[]
System.Xml.XmlNode[]

It would seem to me that this has got to be a bug since the XML infoset that XmlSerializer is consuming should be identical whether it is coming from an XmlTextReader or XmlNodeReader.

There is an obvious workaround (serialize the XmlNode to a MemoryStream, then deserialize from it using an XmlTextReader). Somehow writing then re-parsing the XML that has already been loaded into a DOM seems very ugly and unncessary. Can someone suggest an alternative solution, or an explanation for this behaviour?

Andy
Nov 12 '05 #2
The problem is you are de-serializing into an ArrayList, and you haven't provided any hints to the serializer as to the types of the items in that list.
At De-serialization time, the runtime doesn't know what to de-serialize the various xml nodes into. When you de-serialize from a XmlTextReader, the serializer uses the xsi:type as guesses. When you de-serialize from an XmlNodeReader, you get (surprise!) XmlNodes, which correspond to the attributes and InnerText in that node.

To address this you could simply add some hints to the ArrayList Values. Eg:

public class MyClass
{
[XmlArray("Values")]
[XmlArrayItem("StringValue",typeof(System.String))]
[XmlArrayItem("IntValue",typeof(System.Int32))]

public ArrayList Values = new ArrayList();
}
Doing this you will get the same results using either Reader. If you have objects of completely arbitrary type in the arraylist, then you will want to add an
[XmlArrayItem("Unknown",typeof(System.Object))]

to the list of attributes. This will revert to the behavior of getting an XmlNode[] for that particular arraylist item.

-Dino
"Andy Neilson" <aneilsonNoSpam69AthotmailDotcom> wrote in message news:%2******************@TK2MSFTNGP09.phx.gbl...
I've run across a strange behaviour with XmlSerializer that I'm unable to explain. I came across this while trying to use XmlSerializer to deserialize from a the details of a SoapException. This should have worked fine since the class in question was already being serialized and deserialized as part of a Web service interface. What I found was that by deserializing from an XmlNodeReader instead of an XmlTextReader, XML Serialization doesn't work the same way as when it deserialized from an XmlTextReader.

This is easily reproduced with the following C# code:

using System;
using System.Xml;
using System.Xml.Serialization;
using System.Collections;

public class MyClass
{
public ArrayList Values = new ArrayList();
}

class Class1
{
[STAThread]
static void Main(string[] args)
{
MyClass myClass1 = new MyClass();
myClass1.Values.Add(123);
myClass1.Values.Add("abc");

XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
XmlWriter writer = new XmlTextWriter("temp.xml", System.Text.Encoding.UTF8);
serializer.Serialize(writer, myClass1);
writer.Close();

// Deserializing using an XmlTextReader works fine
MyClass myClass2 = (MyClass)serializer.Deserialize(new XmlTextReader("temp.xml"));
foreach (object value in myClass2.Values) Console.WriteLine(value.ToString());
Console.ReadLine();

// Deserializing using an XmlNodeReader over the same document doesn't work
XmlDocument doc = new XmlDocument();
doc.Load("temp.xml");
MyClass myClass3 = (MyClass)serializer.Deserialize(new XmlNodeReader(doc));
foreach (object value in myClass3.Values) Console.WriteLine(value.ToString());
Console.ReadLine();
}
}

The "temp.xml" file will contain the following:

<?xml version="1.0" encoding="utf-8"?>
<MyClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Values>
<anyType xsi:type="xsd:int">123</anyType>
<anyType xsi:type="xsd:string">abc</anyType>
</Values>
</MyClass>

The output will be:

123
abc

System.Xml.XmlNode[]
System.Xml.XmlNode[]

It would seem to me that this has got to be a bug since the XML infoset that XmlSerializer is consuming should be identical whether it is coming from an XmlTextReader or XmlNodeReader.

There is an obvious workaround (serialize the XmlNode to a MemoryStream, then deserialize from it using an XmlTextReader). Somehow writing then re-parsing the XML that has already been loaded into a DOM seems very ugly and unncessary. Can someone suggest an alternative solution, or an explanation for this behaviour?

Andy
Nov 12 '05 #3
I think you are missing my point. I can't think of any reason why the identical XML infoset represented by an XmlReader would be treated differently depending on whether it is an XmlTextReader reading from a FileStream, or an XmlNodeReader over an XmlDocument. In both cases, the XmlSerializer should have the the identical xsi:type information available to it, so why is it ignored in the XmlNodeReader case?
The problem is you are de-serializing into an ArrayList, and you haven't provided any hints to the serializer as to the types of the items in that list. <<<
There is an excellent hint in the XML in the form of the xsi:type attribute that the XmlSerializer has put there for just that purpose when I serialized the ArrayList. In the XmlTextReader case, the XmlSerializer does exactly what I expect in that it uses its default mappings from xsi:type to simple types, so there should be no need to use type-specific element names. If the XmlTextReader takes the hint, the XmlNodeReader should do so as well!
When you de-serialize from an XmlNodeReader, you get (surprise!) XmlNodes, which correspond to the attributes and InnerText in that node.<<<


I have no idea what you mean by that statement. Regardless of derived type of the XmlReader you are using, the interface presents a forward-only cursor over XmlNodes. Why would an XmlNodeReader present a different set of nodes than XmlTextReader? If XmlNodeReader doesn't present the same nodes as XmlTextReader, could you explain what the difference is? It seems like an important difference that is not at all obvious.

Andy

"Dino Chiesa [Microsoft]" <di****@online.microsoft.com> wrote in message news:uy**************@TK2MSFTNGP09.phx.gbl...
The problem is you are de-serializing into an ArrayList, and you haven't provided any hints to the serializer as to the types of the items in that list.
At De-serialization time, the runtime doesn't know what to de-serialize the various xml nodes into. When you de-serialize from a XmlTextReader, the serializer uses the xsi:type as guesses. When you de-serialize from an XmlNodeReader, you get (surprise!) XmlNodes, which correspond to the attributes and InnerText in that node.

To address this you could simply add some hints to the ArrayList Values. Eg:

public class MyClass
{
[XmlArray("Values")]
[XmlArrayItem("StringValue",typeof(System.String))]
[XmlArrayItem("IntValue",typeof(System.Int32))]

public ArrayList Values = new ArrayList();
}
Doing this you will get the same results using either Reader. If you have objects of completely arbitrary type in the arraylist, then you will want to add an
[XmlArrayItem("Unknown",typeof(System.Object))]

to the list of attributes. This will revert to the behavior of getting an XmlNode[] for that particular arraylist item.

-Dino
"Andy Neilson" <aneilsonNoSpam69AthotmailDotcom> wrote in message news:%2******************@TK2MSFTNGP09.phx.gbl...
I've run across a strange behaviour with XmlSerializer that I'm unable to explain. I came across this while trying to use XmlSerializer to deserialize from a the details of a SoapException. This should have worked fine since the class in question was already being serialized and deserialized as part of a Web service interface. What I found was that by deserializing from an XmlNodeReader instead of an XmlTextReader, XML Serialization doesn't work the same way as when it deserialized from an XmlTextReader.

This is easily reproduced with the following C# code:

using System;
using System.Xml;
using System.Xml.Serialization;
using System.Collections;

public class MyClass
{
public ArrayList Values = new ArrayList();
}

class Class1
{
[STAThread]
static void Main(string[] args)
{
MyClass myClass1 = new MyClass();
myClass1.Values.Add(123);
myClass1.Values.Add("abc");

XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
XmlWriter writer = new XmlTextWriter("temp.xml", System.Text.Encoding.UTF8);
serializer.Serialize(writer, myClass1);
writer.Close();

// Deserializing using an XmlTextReader works fine
MyClass myClass2 = (MyClass)serializer.Deserialize(new XmlTextReader("temp.xml"));
foreach (object value in myClass2.Values) Console.WriteLine(value.ToString());
Console.ReadLine();

// Deserializing using an XmlNodeReader over the same document doesn't work
XmlDocument doc = new XmlDocument();
doc.Load("temp.xml");
MyClass myClass3 = (MyClass)serializer.Deserialize(new XmlNodeReader(doc));
foreach (object value in myClass3.Values) Console.WriteLine(value.ToString());
Console.ReadLine();
}
}

The "temp.xml" file will contain the following:

<?xml version="1.0" encoding="utf-8"?>
<MyClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Values>
<anyType xsi:type="xsd:int">123</anyType>
<anyType xsi:type="xsd:string">abc</anyType>
</Values>
</MyClass>

The output will be:

123
abc

System.Xml.XmlNode[]
System.Xml.XmlNode[]

It would seem to me that this has got to be a bug since the XML infoset that XmlSerializer is consuming should be identical whether it is coming from an XmlTextReader or XmlNodeReader.

There is an obvious workaround (serialize the XmlNode to a MemoryStream, then deserialize from it using an XmlTextReader). Somehow writing then re-parsing the XML that has already been loaded into a DOM seems very ugly and unncessary. Can someone suggest an alternative solution, or an explanation for this behaviour?

Andy
Nov 12 '05 #4
I think you are missing my point. I can't think of any reason why the identical XML infoset represented by an XmlReader would be treated differently depending on whether it is an XmlTextReader reading from a FileStream, or an XmlNodeReader over an XmlDocument. In both cases, the XmlSerializer should have the the identical xsi:type information available to it, so why is it ignored in the XmlNodeReader case?
The problem is you are de-serializing into an ArrayList, and you haven't provided any hints to the serializer as to the types of the items in that list. <<<
There is an excellent hint in the XML in the form of the xsi:type attribute that the XmlSerializer has put there for just that purpose when I serialized the ArrayList. In the XmlTextReader case, the XmlSerializer does exactly what I expect in that it uses its default mappings from xsi:type to simple types, so there should be no need to use type-specific element names. If the XmlTextReader takes the hint, the XmlNodeReader should do so as well!
When you de-serialize from an XmlNodeReader, you get (surprise!) XmlNodes, which correspond to the attributes and InnerText in that node.<<<


I have no idea what you mean by that statement. Regardless of derived type of the XmlReader you are using, the interface presents a forward-only cursor over XmlNodes. Why would an XmlNodeReader present a different set of nodes than XmlTextReader? If XmlNodeReader doesn't present the same nodes as XmlTextReader, could you explain what the difference is? It seems like an important difference that is not at all obvious.

Andy

"Dino Chiesa [Microsoft]" <di****@online.microsoft.com> wrote in message news:uy**************@TK2MSFTNGP09.phx.gbl...
The problem is you are de-serializing into an ArrayList, and you haven't provided any hints to the serializer as to the types of the items in that list.
At De-serialization time, the runtime doesn't know what to de-serialize the various xml nodes into. When you de-serialize from a XmlTextReader, the serializer uses the xsi:type as guesses. When you de-serialize from an XmlNodeReader, you get (surprise!) XmlNodes, which correspond to the attributes and InnerText in that node.

To address this you could simply add some hints to the ArrayList Values. Eg:

public class MyClass
{
[XmlArray("Values")]
[XmlArrayItem("StringValue",typeof(System.String))]
[XmlArrayItem("IntValue",typeof(System.Int32))]

public ArrayList Values = new ArrayList();
}
Doing this you will get the same results using either Reader. If you have objects of completely arbitrary type in the arraylist, then you will want to add an
[XmlArrayItem("Unknown",typeof(System.Object))]

to the list of attributes. This will revert to the behavior of getting an XmlNode[] for that particular arraylist item.

-Dino
"Andy Neilson" <aneilsonNoSpam69AthotmailDotcom> wrote in message news:%2******************@TK2MSFTNGP09.phx.gbl...
I've run across a strange behaviour with XmlSerializer that I'm unable to explain. I came across this while trying to use XmlSerializer to deserialize from a the details of a SoapException. This should have worked fine since the class in question was already being serialized and deserialized as part of a Web service interface. What I found was that by deserializing from an XmlNodeReader instead of an XmlTextReader, XML Serialization doesn't work the same way as when it deserialized from an XmlTextReader.

This is easily reproduced with the following C# code:

using System;
using System.Xml;
using System.Xml.Serialization;
using System.Collections;

public class MyClass
{
public ArrayList Values = new ArrayList();
}

class Class1
{
[STAThread]
static void Main(string[] args)
{
MyClass myClass1 = new MyClass();
myClass1.Values.Add(123);
myClass1.Values.Add("abc");

XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
XmlWriter writer = new XmlTextWriter("temp.xml", System.Text.Encoding.UTF8);
serializer.Serialize(writer, myClass1);
writer.Close();

// Deserializing using an XmlTextReader works fine
MyClass myClass2 = (MyClass)serializer.Deserialize(new XmlTextReader("temp.xml"));
foreach (object value in myClass2.Values) Console.WriteLine(value.ToString());
Console.ReadLine();

// Deserializing using an XmlNodeReader over the same document doesn't work
XmlDocument doc = new XmlDocument();
doc.Load("temp.xml");
MyClass myClass3 = (MyClass)serializer.Deserialize(new XmlNodeReader(doc));
foreach (object value in myClass3.Values) Console.WriteLine(value.ToString());
Console.ReadLine();
}
}

The "temp.xml" file will contain the following:

<?xml version="1.0" encoding="utf-8"?>
<MyClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Values>
<anyType xsi:type="xsd:int">123</anyType>
<anyType xsi:type="xsd:string">abc</anyType>
</Values>
</MyClass>

The output will be:

123
abc

System.Xml.XmlNode[]
System.Xml.XmlNode[]

It would seem to me that this has got to be a bug since the XML infoset that XmlSerializer is consuming should be identical whether it is coming from an XmlTextReader or XmlNodeReader.

There is an obvious workaround (serialize the XmlNode to a MemoryStream, then deserialize from it using an XmlTextReader). Somehow writing then re-parsing the XML that has already been loaded into a DOM seems very ugly and unncessary. Can someone suggest an alternative solution, or an explanation for this behaviour?

Andy
Nov 12 '05 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Zion Zadik | last post by:
Dear all, I have a set of c# data classes which i need to fill their data from xml files. serialization looks to be the best way to accomplish this task. Since the data classes are compiled and...
16
by: Bob Rock | last post by:
Hello, when serializing an array of elements of a class Classname using XmlSerializer.Serialize() I get an XML like the following: <?xml version="1.0"> <ArrayOfClassname> ....... ..........
2
by: magister | last post by:
Hello I got this working but it is not how I really want it, basically I have an xml file which has a root of <test> and can be filled with 3 different types of <question> elements with different...
3
by: stax | last post by:
Hello, can somebody tell me how to serialize/deserialize a object containing a multi line string using the XmlSerializer class. One of the both windows linefeed chars get dumped somewhere down...
0
by: William Stacey [MVP] | last post by:
Had a method that got some string info from mp3 tags in N files and serializes this class and deserializes at other side. Works ok except sometimes get chars that choke the XmlSerializer. After...
3
by: Schorschi | last post by:
The following code works fine until I check the .CanDeserialize flag The exact same code in C# works, but in VB .NET? AUGH! HELP! ---------------------------------- Public Function...
1
by: Yewen Tang | last post by:
I have a schema file datamodel.xsd, element "properties" is declared as a type of "baseProperty". The schema file also defines "derivedProperty" is a derived type of "baseProperty". <?xml...
0
by: PSingh | last post by:
Hi, I know this is a frequently asked question but have tried several combinations and cant seem to figure this out. I am serializing my object as follows: XmlSerializer serializer = new...
6
by: Andrew | last post by:
I am using an XmlSerializer to save some settings and I have discovered that when a string is saved containing a cr+nl it is replaced with just a newline when loading back in. I am no expert with...
2
by: DJRhino | last post by:
Was curious if anyone else was having this same issue or not.... I was just Up/Down graded to windows 11 and now my access combo boxes are not acting right. With win 10 I could start typing...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 4 Oct 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM) The start time is equivalent to 19:00 (7PM) in Central...
0
by: Aliciasmith | last post by:
In an age dominated by smartphones, having a mobile app for your business is no longer an option; it's a necessity. Whether you're a startup or an established enterprise, finding the right mobile app...
2
by: giovanniandrean | last post by:
The energy model is structured as follows and uses excel sheets to give input data: 1-Utility.py contains all the functions needed to calculate the variables and other minor things (mentions...
3
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be using a very simple database which has Form (clsForm) & Report (clsReport) classes that simply handle making the calling Form invisible until the Form, or all...
1
by: Teri B | last post by:
Hi, I have created a sub-form Roles. In my course form the user selects the roles assigned to the course. 0ne-to-many. One course many roles. Then I created a report based on the Course form and...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 1 Nov 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM) Please note that the UK and Europe revert to winter time on...
0
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be focusing on the Report (clsReport) class. This simply handles making the calling Form invisible until all of the Reports opened by it have been closed, when it...
0
isladogs
by: isladogs | last post by:
The next online meeting of the Access Europe User Group will be on Wednesday 6 Dec 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, Mike...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.