469,286 Members | 2,476 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,286 developers. It's quick & easy.

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 10974
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 discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

2 posts views Thread by magister | last post: by
reply views Thread by William Stacey [MVP] | last post: by
1 post views Thread by CARIGAR | last post: by
reply views Thread by zhoujie | last post: by
reply views Thread by suresh191 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.