Xml serialization, arrays, XmlAnyAttribute

G

Guest

Hi...

I was trying to deserialize objects from xml that contain a couple of
arrays. In the xml, at least, I was trying to express some default/static
members to the array as attributes on the array bracket (e.g.
....
<Foobars defaultFoo="bar">
<Foobar>Foo</Foobar>
<Foobar></Foobar>
</Foobars>
....

and in the class to be deserialized I have
public Foobar[] Foobars {}
)

I was experimenting with [XmlAnyAttribute], [XmlAttribute], etc and I found
that the attribute defaultFoo just vaporizes. It doesn't show up in the
any-attribute array for the container class nor does it show up in the
unknown attributes array for the Foobar instances.

Ideally, what I'd like to have happen is to direct defaultFoo directed into
public class Foobar
{
public static string defaultFoo;
}
but at the moment I'm not having luck getting it to show up anywhere.

Any pointers?

Thanks
Mark
 
S

Steven Cheng[MSFT]

Hi Mark,

From your description, you're using the .NET XmlSerializer to
serialize/deserize some object Arrays and the serialized XML element has
some attributes, you'e re wondering how to deserize those attributes into
NET class's static members, correct?

Based on my understanding, the .NET Xmlserializer based xml serialization
only working for mapping XML document/elements to .NET class
instances(instance members), static members are not supported by the
serialization engine.

And for your scenario that need to pickup some attributes from XML document
and store into class's static members, I think you can consider either of
the following means:

1. There are some community members who suggest use class instance members
to wrapper static members. Thus, when setting the instance members, the
static members are also updated. This is somewhat a trick, here is a thread
mentioned this:

http://www.thescripts.com/forum/thread172026.html

2. Or if you're using .net framework 2.0, you can utilize the
IXmlSerialization interface to completely control the serialization of a
class(which implement this interface). You can completely write the code
logic on how to class generate and write out its serialized XML output and
how to read deserialized input xml from xmlreader and populate the class
fields. here are some reference introducing this interface:

http://www.devx.com/dotnet/Article/29720

#IXmlSerializable Interface
http://msdn2.microsoft.com/en-us/library/System.Xml.Serialization.IXmlSerial
izable.aspx

Hope this helps. If you have any further questions, welcome to discuss here.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead



==================================================

Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.



Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.

==================================================


This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Steven...

Actually, that doesn't summarize my main questions. I'm sorry I wasn't more
clear. My main questions were around

1) how XmlSerializer handles arrays of objects - the convention is to have
an array type property/member (e.g. public Foobar[] Foobars {}). That
serializes/deserializes as <Foobars><Foobar/><Foobar/></Foobars>.

and
2) how [XmlAnyAttribute] works.

The use case I was trying to implement involved adding an xml attribute to
the array wrapper (e.g. <Foobars default="foo">...</Foobars>

If I have any single member of a serialized object, I can change the xml
serialization with [XmlAttribute] (to make the member an attribute on the
resulting xml) or [XmlElement].

The problem I have is that if I mark a member/property with [XmlAttribute]
it becomes an attribute on the parent xml node not on another child
member/property.
For example the Foobars mentioned previously is a child member array of
another object, so the whole xml would be something like
<ObjectParent>
....
<Foobars>
<Foobar/>
</Foobars>
</ObjectParent>

I'd like to get the xml attribute associated with the array in the xml; I
can work out how to push the value around later.

I tried using [XmlAnyAttribute] to capture that extra attribute on <Foobars
default="..."> since it really didn't fit anywhere else. The problem there
was that putting an attribute where I want doesn't show up in any
[XmlAnyAttribute] bucket; it just disappears.

I tried putting an [XmlAnyAttribute] bucket in ObjectParent and in the
definition for Foobar but neither one saw the default="" attribute.

I'll go look at the article about writing a whole serializer.

Thanks
Mark
 
S

Steven Cheng[MSFT]

Hi Mark,

Any progress on this?

For the two questions you mentioned in last reply, I've performed some
further research and here are some of what I found and understanding:

**1) how XmlSerializer handles arrays of objects - the convention is to
have
an array type property/member (e.g. public Foobar[] Foobars {}). That
serializes/deserializes as <Foobars><Foobar/><Foobar/></Foobars>.
=====================================
To take an Array member, you should use the "XmlArrayAttribute" to decorate
the member property, and "XmlArrayItemAttribute" can help further describe
the array item objects. Here is a test class I've made which can serialize
and deserialize a class which take a member property of a custom collection
class(array of another custom class):

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
namespace XMLSerializeApp
{
[XmlRoot("EmployeeElement")]
public class Employee
{
private string _firstname;
private string _lastname;

[XmlAttribute("firstName")]
public string FirstName
{
get { return _firstname; }
set { _firstname = value; }
}

[XmlAttribute("lastName")]
public string LastName
{
get { return _lastname; }
set { _lastname = value; }
}

public Employee() { }

public Employee(string fn, string ln)
{
_firstname = fn;
_lastname = ln;
}
}



[XmlRoot("EmployeeCollectionElement")]
public class EmployeeCollection : CollectionBase
{



public Employee this[int index]
{
get
{
return ((Employee)List[index]);
}
set
{
List[index] = value;
}
}

public int Add(Employee value)
{
return (List.Add(value));
}

public int IndexOf(Employee value)
{
return (List.IndexOf(value));
}

public void Insert(int index, Employee value)
{
List.Insert(index, value);
}

public void Remove(Employee value)
{
List.Remove(value);
}

public bool Contains(Employee value)
{
// If value is not of type Employee, this will return false.
return (List.Contains(value));
}

protected override void OnInsert(int index, Object value)
{
// Insert additional code to be run only when inserting values.
}

protected override void OnRemove(int index, Object value)
{
// Insert additional code to be run only when removing values.
}

protected override void OnSet(int index, Object oldValue, Object
newValue)
{
// Insert additional code to be run only when setting values.
}

protected override void OnValidate(Object value)
{
if (value.GetType() != typeof(Employee))
throw new ArgumentException("value must be of type
Employee.", "value");
}

}

[XmlRoot("WorkGroupElement")]
public class WorkGroup
{
private string _name;
private EmployeeCollection _emps;

[XmlAttribute("name")]
public string Name
{
get { return _name; }
set { _name = value; }
}

[XmlAnyAttribute]
public XmlAttribute[] XAttributes;



[XmlArray("GroupMembers")]
public EmployeeCollection Employees
{
get { return _emps; }
set { _emps = value; }
}

public WorkGroup()
{ _emps = new EmployeeCollection();}

public WorkGroup(string name)
: this()
{
_name = name;
}
}

}


**2) how [XmlAnyAttribute] works.
It seems the "XmlAnyAttribute attribute" only apply and work on the top
level xml element( that means the type you supply in the XmlSerializer's
constructor). for example, as for the classes I put above, If I deserlize
the "WorkGroup" class, only the "XmlAnyAttribute" applied on WorkGroup
class's member property will work(collect the attributes in WorkGroup
element). If the "XmlAnyAttribute" is applied in nested property's
class(such as the EmployeeCollection, it won't work ). This seems to be a
fixed behavior of the xmlSerializer.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Steven...

Thanks for taking the time to work up an example. If I'm reading it
correctly, you got near what I was looking to do (adding an xml attribute to
an array) by adding another node to hang it on. In other words, I was
looking to have something like

<GroupMembers name="something">
<Employee>...</Employee>
</GroupMembers>

while your example would produce something like
<WorkGroupElement name="something">
<GroupMembers>
<Employee>...</Employee>
</GroupMembers>
</WorkGroupElement>

In short it doesn't seem like the form I wanted is possible with the given
tools unless I write a completely custom serializer/deserializer. The least
expensive work-around would be to add an additional parent element, as you
did.

Thanks for all of your time on the questions.

Mark
 
S

Steven Cheng[MSFT]

Thanks for your reply Mark,

Yes, due to the "XmlAnyAttribute attribute" behavior, if we want to make
Custom collection/array an member of another class and also apply dynamic
attributes on them, we may need to add a wrapper class(as XmlSerializer
only look for attributes for the root class).

Also, if you want to manually do the serialization/deserialization work, I
think you can consider create a custom collection class and implement the
"IXmlSerializable" interface(I mentioned earlier), thus, you can also deal
with the underlying xmlreader/xmlwriter to control the
serialization/deserialzation without write a custom Xmlserializer. How do
you think?

Anyway, please feel free to post here if there is anything else we can help.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead

This posting is provided "AS IS" with no warranties, and confers no rights.
 
S

Steven Cheng[MSFT]

Hi Mark,

Any further questions on this? If so, please feel free to let me know.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


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

Top