XML Serialization of ListArray

G

George Ter-Saakov

I have 2 classes one is document and another is collection of documents.
When i am trying to use XmlSerializer to serialize class which has
clsDcoumentIds member variable i am getting an exception
"System.InvalidOperationException: The type clsDocumentId was not expected."


public class clsDocumentId
{
string _sDocumentId;
public clsDocumentId() {}

[XmlElement("DocumentId")]
public string DocumentId {
get {return _sDocumentId;}
set { _sDocumentId = value;}
}
}

public class clsDocumentIds
{
ArrayList _lstDocumentIds = new ArrayList();

[XmlArrayAttribute(ElementName="DocumentId")]
public ArrayList DocumentIds {
get {return _lstDocumentIds;}
set {_lstDocumentIds = value;}
}
}


What is the solution?

PS: Also if i follow a suggestion VS comipler gives to use
"Use the XmlInclude or SoapInclude attribute to specify types that are not
known statically."

I get incorrect XML

<DocumentIds>
<DocumentId>
<anyType xsi:type="clsDocumentId">
<DocumentId>aasds</DocumentId>
</anyType>
</DocumentId>
</DocumentIds>


Thanks.
George.
 
S

Steven Cheng[MSFT]

Hi George,


Thank you for the response. Regarding on the issue, I am
finding proper resource to assist you and we will update as soon as posible.

Regards,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security(This posting is provided "AS IS",
with no warranties, and confers no rights.)
 
S

Steven Cheng[MSFT]

Hi George,


Thank you for using MSDN Newsgroup! My name is Steven, and I'll be
assisting you on this issue.
From your description, you have two custom classes, one is a collection
class which contains a list of the other. However, when you use the
XmlSerializer to serialize some certain object which contains some member
of the two classes, there occurs the "System.InvalidOperationException: The
type clsDocumentId was not expected."
If there is anything I misunderstood, please feel free to let me know.


I've done some tests on the code provided and found that the problem is due
to some incorrect XmlSerialize attributes in the "clsDocumentIds" class.
1. For such class which contains a member that is type of Array or a
collection, an ArrayList, or any class that implements the IEnumerable
interface you need to specify the type of the item which is contained in
the array or list or collection.
For example:

[XmlArrayItem(typeof(clsDocumentId),ElementName = "MyDocumentId")]
ArrayList _lstDocumentIds = new ArrayList();

in the above code, I specify the "clsDocumentId" class's type as the type
of the arraylist member's item type

2. If you want to specify some attributes for the Array or ArrayList member
itself , you need to use the "XmlArray" attribute, For example:
[XmlArray(ElementName = "MyDocumentIds",
Namespace = "", IsNullable = true)]
ArrayList _lstDocumentIds = new ArrayList();

3. In addtion, as for your situation, in the clsDocumentIds class, you use
a private member "_lstDocumentIds" and a public property "DocumentIds"
which are actually the same member. Then, you must specify the
XmlAttributes for both of them as the same value, not only set the Public
property member's.

If you need more detailed instruction on how to use XmlSerialer to
serialize a class and how to use Attributes to control serializer, you may
view the following reference in MSDN:

#Examples of XML Serialization
http://msdn.microsoft.com/library/en-us/cpguide/html/cpconanexampleofxmlseri
alizationwithxmlserializer.asp?frame=true

#Controlling XML Serialization Using Attributes
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/htm
l/cpconanexampleofxmlserializationwithxmlserializer.asp

Also, here is the sample classes I used to test, please check it out if you
have anything unclear in my above description:

------------------clsDocumentId class-----------
public class clsDocumentId
{

string _sDocumentId;

public clsDocumentId() {}

[XmlElement("DocumentId")]
public string DocumentId
{
get {return _sDocumentId;}
set { _sDocumentId = value;}
}
}

-----------------clsDocumentIds class ---------------------
public class clsDocumentIds
{


[XmlArrayItem(typeof(clsDocumentId),ElementName = "MyDocumentId")]
[XmlArray(ElementName = "MyDocumentIds",
Namespace = "", IsNullable = true)]
ArrayList _lstDocumentIds = new ArrayList();



[XmlArrayItem(typeof(clsDocumentId),ElementName = "MyDocumentId")]
[XmlArray(ElementName = "MyDocumentIds",
Namespace = "", IsNullable = true)]
public ArrayList DocumentIds
{
get {return _lstDocumentIds;}
set {_lstDocumentIds = value;}
}

}

--------------------------Container class-------------------------
public class Container
{
public Container()
{

}

public string DocumentName = "Default Document";
public clsDocumentIds Documents = new clsDocumentIds();
}


If you still have any questions on this issue, please feel free to let me
know.


Regards,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
G

George Ter-Saakov

Thanks for your reply.
An i do have one issue.
The code creates following XML

<DocumentIds>
<MyDocumentId>
<DocumentId>test1</DocumentId>
</MyDocumentId>
<MyDocumentId>
<DocumentId>test2</DocumentId>
</MyDocumentId>
</DocumentIds>

It's understandable.
It wraps each element of _lstDocumentIds into <MyDocumentId> and then
outputs each DocumentId object.

It's ok if clsDocumentId were a complex type. But it's just a string and i
wish i could avoid the MyDocumentId tag.

So my final XML will be like
<DocumentIds>
<DocumentId>test1</DocumentId>
<DocumentId>test2</DocumentId>
</DocumentIds>

How can i do that?

Thanks.
George.

Steven Cheng said:
Hi George,


Thank you for using MSDN Newsgroup! My name is Steven, and I'll be
assisting you on this issue.
From your description, you have two custom classes, one is a collection
class which contains a list of the other. However, when you use the
XmlSerializer to serialize some certain object which contains some member
of the two classes, there occurs the "System.InvalidOperationException: The
type clsDocumentId was not expected."
If there is anything I misunderstood, please feel free to let me know.


I've done some tests on the code provided and found that the problem is due
to some incorrect XmlSerialize attributes in the "clsDocumentIds" class.
1. For such class which contains a member that is type of Array or a
collection, an ArrayList, or any class that implements the IEnumerable
interface you need to specify the type of the item which is contained in
the array or list or collection.
For example:

[XmlArrayItem(typeof(clsDocumentId),ElementName = "MyDocumentId")]
ArrayList _lstDocumentIds = new ArrayList();

in the above code, I specify the "clsDocumentId" class's type as the type
of the arraylist member's item type

2. If you want to specify some attributes for the Array or ArrayList member
itself , you need to use the "XmlArray" attribute, For example:
[XmlArray(ElementName = "MyDocumentIds",
Namespace = "", IsNullable = true)]
ArrayList _lstDocumentIds = new ArrayList();

3. In addtion, as for your situation, in the clsDocumentIds class, you use
a private member "_lstDocumentIds" and a public property "DocumentIds"
which are actually the same member. Then, you must specify the
XmlAttributes for both of them as the same value, not only set the Public
property member's.

If you need more detailed instruction on how to use XmlSerialer to
serialize a class and how to use Attributes to control serializer, you may
view the following reference in MSDN:

#Examples of XML Serialization
http://msdn.microsoft.com/library/en-us/cpguide/html/cpconanexampleofxmlseri
alizationwithxmlserializer.asp?frame=true

#Controlling XML Serialization Using Attributes
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/htm
l/cpconanexampleofxmlserializationwithxmlserializer.asp

Also, here is the sample classes I used to test, please check it out if you
have anything unclear in my above description:

------------------clsDocumentId class-----------
public class clsDocumentId
{

string _sDocumentId;

public clsDocumentId() {}

[XmlElement("DocumentId")]
public string DocumentId
{
get {return _sDocumentId;}
set { _sDocumentId = value;}
}
}

-----------------clsDocumentIds class ---------------------
public class clsDocumentIds
{


[XmlArrayItem(typeof(clsDocumentId),ElementName = "MyDocumentId")]
[XmlArray(ElementName = "MyDocumentIds",
Namespace = "", IsNullable = true)]
ArrayList _lstDocumentIds = new ArrayList();



[XmlArrayItem(typeof(clsDocumentId),ElementName = "MyDocumentId")]
[XmlArray(ElementName = "MyDocumentIds",
Namespace = "", IsNullable = true)]
public ArrayList DocumentIds
{
get {return _lstDocumentIds;}
set {_lstDocumentIds = value;}
}

}

--------------------------Container class-------------------------
public class Container
{
public Container()
{

}

public string DocumentName = "Default Document";
public clsDocumentIds Documents = new clsDocumentIds();
}


If you still have any questions on this issue, please feel free to let me
know.


Regards,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
S

Steven Cheng[MSFT]

Hi George,

Thank you for the response. As for the problem you metioned in the reply,
I've reviewed on the XmlSerialer and the XmlSerialize related attributes in
the MSDN, and here is some of my suggestions:

As for the output as below:
<DocumentIds>
<MyDocumentId>
<DocumentId>test1</DocumentId>
</MyDocumentId>
<MyDocumentId>
<DocumentId>test2</DocumentId>
</MyDocumentId>
</DocumentIds>

It is the serialize output of a arraylist or array of clsDocumentId. We
could see that every clsDocumentId object is serialize as:
<MyDocumentId>
<DocumentId>test1</DocumentId>
</MyDocumentId>
So the problem you mentioned is mainly due to how the clsDocumentId class's
instance object is serialized. In the output result above, the clsDocument
is serialized as a <MyDocumentId> element which contains a <DocumentId> sub
element and the subelement's inner text is the member string's value. In
fact the <MyDocumentId> element is used to specify the clsDocumentId
object, this element is necessary because it indicate that this is an
object of a certain type no matter the object is a complex object or as
simple as a string. So we can't omit it, otherwise, there 'll occur
prolbem when deserializing the xml back to the certain object. Then, as
for the <DocumentId> element, it indicate that there is a member in the
object and the member is named "DocumentId" , its value is "test2". Since
there're different node types in XML such as element node, attribute node,
and textnode, as for the problem you mentioned(to omit simplize the
DocumentId element for it is just a string value) , I think we could
generate a solution focus on the <DocumentId>test1</DocumentId> child node.
In XML , a testnode is just a plain text with out begin tag and end tag. So
we could simple specify the clsDocumentId class's
"DocumentId" member as a "TextNode"(use the [XmlText(Type =
typeof(string))] attribute] so that it'll be serialized as a textnode. Here
is the modified clsDocumentId class's source:
public class clsDocumentId
{
[XmlText(Type = typeof(string))]
string _sDocumentId;

public clsDocumentId() {}


[XmlText(Type = typeof(string))]
public string DocumentId
{
get {return _sDocumentId;}
set { _sDocumentId = value;}
}
}
you may have a test to see whether it works. Also, if you need some more
info on the [XmlText......] attribute, you can view the following link for
reference:

http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemXmlSerializati
onXmlTextAttributeClassTopic.asp?frame=true

And here is some web links for some XML reference on the Xml Node:
#12 XML DOM Node types
http://www.topxml.com/xml_dom/12_xml_dom_node_types.asp

I think they'll also be helpful to you.



Regards,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
G

George Ter-Saakov

Great thanks.

did not know that XmlText attribute exists.

George.

Steven Cheng said:
Hi George,

Thank you for the response. As for the problem you metioned in the reply,
I've reviewed on the XmlSerialer and the XmlSerialize related attributes in
the MSDN, and here is some of my suggestions:

As for the output as below:
<DocumentIds>
<MyDocumentId>
<DocumentId>test1</DocumentId>
</MyDocumentId>
<MyDocumentId>
<DocumentId>test2</DocumentId>
</MyDocumentId>
</DocumentIds>

It is the serialize output of a arraylist or array of clsDocumentId. We
could see that every clsDocumentId object is serialize as:
<MyDocumentId>
<DocumentId>test1</DocumentId>
</MyDocumentId>
So the problem you mentioned is mainly due to how the clsDocumentId class's
instance object is serialized. In the output result above, the clsDocument
is serialized as a <MyDocumentId> element which contains a <DocumentId> sub
element and the subelement's inner text is the member string's value. In
fact the <MyDocumentId> element is used to specify the clsDocumentId
object, this element is necessary because it indicate that this is an
object of a certain type no matter the object is a complex object or as
simple as a string. So we can't omit it, otherwise, there 'll occur
prolbem when deserializing the xml back to the certain object. Then, as
for the <DocumentId> element, it indicate that there is a member in the
object and the member is named "DocumentId" , its value is "test2". Since
there're different node types in XML such as element node, attribute node,
and textnode, as for the problem you mentioned(to omit simplize the
DocumentId element for it is just a string value) , I think we could
generate a solution focus on the <DocumentId>test1</DocumentId> child node.
In XML , a testnode is just a plain text with out begin tag and end tag. So
we could simple specify the clsDocumentId class's
"DocumentId" member as a "TextNode"(use the [XmlText(Type =
typeof(string))] attribute] so that it'll be serialized as a textnode. Here
is the modified clsDocumentId class's source:
public class clsDocumentId
{
[XmlText(Type = typeof(string))]
string _sDocumentId;

public clsDocumentId() {}


[XmlText(Type = typeof(string))]
public string DocumentId
{
get {return _sDocumentId;}
set { _sDocumentId = value;}
}
}
you may have a test to see whether it works. Also, if you need some more
info on the [XmlText......] attribute, you can view the following link for
reference:

http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemXmlSerializati
onXmlTextAttributeClassTopic.asp?frame=true

And here is some web links for some XML reference on the Xml Node:
#12 XML DOM Node types
http://www.topxml.com/xml_dom/12_xml_dom_node_types.asp

I think they'll also be helpful to you.



Regards,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,825
Latest member
VernonQuy6

Latest Threads

Top