Hi,
I need to represent something like
public struct MyStruct
{
public string MyProp1;
public string MyProp2;
}
with the only intent to serialize its data into
<a:MyStruct>
<a:MyProp1>...</a:MyProp1>
<a:MyProp2>...</a:MyProp2>
</a:MyStruct>
I can do it this way using struct or simple class, and providing something like ToString and manually create the xml string.
However, wouldn't be better to represent it using some xml classes I was trying to inherit form XmlElement, however its protected constructor prevents me from manually constructing the childs.
I would like the class to be inheritable and allow inheritors to add more childs.
Thanks for any ideas.

representing XmlElement
ChrisCow
XmlSerialization is the mechanism used by Visual Studio to create a Web Service client proxy.
VS reads the schema from the WSDL and creates a serializable .Net class. In your code you populate this .Net class and call the Web Service passing the .Net class as a parameter. The underlying code will serialize this .Net class into Xml for transport across the wire.
Jim TheGreat
en.. it a great idea.
We can have the XmlSerializer create prefix declarations and qualified names instead of repeating namespace declarations on every element or attribute. The first approach puts the control over prefix declarations inside the serialized object. The XmlSerializer checks objects it serializes for a field of type XmlSerializerNamespaces adorned with an XmlNamespaceDeclarations attribute. If it finds such a field, it writes the prefix declarations contained in the XmlNamespaceDeclarations object with the top element of the object graph. Whenever a field or child object references a namespace declared in the XmlNamespaceDeclarations, the XmlSerializer generates the declared prefix instead of writing out another local namespace declaration.
public class MyLock
{
[XmlElement(Namespace="mynamespace")]
public Scope scope;
//etc
[XmlElement(Namespace="mynamespace1")]
public string name;
[XmlNamespaceDeclarations]
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
/// maybe will be hidden ,it only to xmlserializer
public XmlSerializerNamespaces NamespacesHelper
{
get
{
///singleton for more well performance,
if (this.m_Namespaces == null)
{
this.m_Namespaces = new XmlSerializerNamespaces();
this.m_Namespaces.Add("xing", "mynamespace");
this.m_Namespaces.Add("ing", "mynamespace1");
}
return this.m_Namespaces;
}
set
{
this.m_Namespaces = value;
}
}
}
more detail see
http://www.topxml.com/xmlserializer/xmlserializernamespaces.asp
MOK123
Wow, that seems nice. :)
Two little questions - any difference between using fields and properties I found some recomendations to prefer properties, however I don't need to do anything with the value than store it. Serialized are only public members, aren't they So if I use private variables being accessed through properties, I would have to put ....mmm or I can have this hidden Helper properties as store of the visible properties.. that's ok.
The second question. In the OtherDocument class... I expect I can specify the container element which will be rendered using [XmlElement]("hislock") public MyLock mylock, but, can I apply it to the class I mean to define in which xml element will the MyLock container always render...
Thanks again, guys!
Gordon7502
Hello Greg4,
i absolutely agree your doing.
but, there is a little change i will post.
1.if the timeout is a field , when deserializing is happen, how deserialize the TimeOut property
and if using XmlSerializer to serialize object to xml stream, it's not necessary that assign Serializable attribute to class, but it 's necessary for Binary Serializer and SOAP Serializer.
public enum Scope
{
local,
global
}
[Serializable] //this attribute is not necessary
public class MyLock
{
public Scope scope;
[XmlElement("readonly")]
public bool readOnly;
public string TimeOutXmlHelper[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
/// we can use this attribute to prevent this field show in IntelliSense Box, it maybe useful,
/// because this field is only use to XmlSerializer, at Runtime ,we use TimeOut field;
[XmlElement("TimeOut")]]
{
get
{
if (this.TimeOut== TimeSpan.Zero) return null;
else if (this.TimeOut == TimeSpan.MaxValue) return = "infinity";
return "Second-" + this.TimeOut.TotalSeconds;
}
set
{
if(value == "infinity")
{
this.TimeOut = TimeSpan.MaxValue;
return;
}
string _timespan = value.Substring("Second-".Length);
this.TimeOut = TimeSpan.Parse(_timespan);
}
}
[XmlArray("ids")]
[XmlArrayItem("id",typeof(GUID))]
public List<Guid> ids;
[XmlIgnore]
public TimeSpan TimeOut;
}
And
[Serializable]
public class OtherDocument
{
public string name;
public MyLock mylock;
}
chrism12
To use prefixes you need to declare the appropriate namespace to each element and use an XmlSerializerNamespaces object.
[Serializable, XmlRoot(ElementName="lock", Namespace="mynamespace")]
public class MyLock
{
[XmlElement(Namespace="mynamespace")]
public Scope scope;
//etc
}
XmlSerializerNamespaces xmlNamespaces = new XmlSerializerNamespaces();
xmlNamespaces.Add("a", "mynamespace");
serializer.Serialize(output, mylock, xmlNamespaces);
To skip fields or properties during serialization use the XmlIgnoreAttribute
[XmlIgnore]
public string timeOut;
Martin00
The problem is the serialization of a boolean, this will always produce an output
By changing the type of the object being serialised to string you have more control over the output
Here is a quick fix, the resulting Xml will contain either an <exclusive> node or a <shared> node
public
class LockScope{
[XmlElement("exclusive")]
public string xmlExclusive;
[XmlElement("shared")]
public string xmlShared;
[XmlIgnore]
public bool Exclusive
{
get { return (xmlExclusive == String.Empty true:false); }
set
{
xmlExclusive = String.Empty;
xmlShared = null;
}
}
[XmlIgnore]
public bool Shared
{
get { return xmlShared == String.Empty true:false; }
set
{
xmlShared = String.Empty;
xmlExclusive = null;
}
}
}
MNorbex
And third little question which arised when I started realizing it, all of my elements have to have a prefix, but I didn't find any attribute which I can apply to the whole class - do I have to specify XmlElement("ns:myelement") on each member
Edit: oh no, my ns:myelement is transferred into ns_x003A_myelement :( How can I set the prefix
--
If I have catched it, returning null on string property causes not to include that tag during serialization at all
Edit: however boolean value serializes into true/false .. how can I serialize it as include/exclude element
--
Ah, I know I have stupid questions... but if I can join these classes together, I could represent a whole xml document which I expect an deserialize it whole at once into my classes. However, I see two problems. First, how will be handled if the source xml would have my prefix encoded as namespace in some parent element And the second, how can I make the deserializer to ignore the elements which do not fit into my structs
IanG
How about something like this:
public
enum Scope{
local,
global
}
[
Serializable]public class MyLock
{
public Scope scope;
[XmlElement("readonly")]
public bool readOnly;
public string timeout;
[XmlElement("id")]
public List<Guid> ids;
[XmlIgnore]
public TimeSpan TimeOut
{
set
{
if (value == TimeSpan.Zero) this.timeout = null;
else if (value == TimeSpan.MaxValue) this.timeout = "infinity";
else this.timeout = "Second-" + value.TotalSeconds;
}
}
}
And
[Serializable]
public class OtherDocument
{
public string name;
public MyLock mylock;
}
Have you seen the xsd.exe tool, very useful for converting xml schemas (xsd) in to .Net classes.
ericmar
Greg4, Thank you for the XmlSerializerNamespaces hint.
I'm sorry I asked so many questions at once.
XmlIgnore - if you are referencing to the boolean value, I need to exclude the element in xml only if the value is false. From your help I constructed something like:
[XmlRoot(ElementName="lockscope", Namespace="ns:")]
public class LockScope
{
[EditorBrowsable(EditorBrowsableState.Never)]
[XmlElement("exclusive")]
public bool xmlExclusive;
[EditorBrowsable(EditorBrowsableState.Never)]
[XmlElement("shared")]
public bool xmlShared;
[XmlIgnore]
public bool Exclusive
{
get { return xmlExclusive; }
set
{
xmlExclusive = value;
xmlShared = !value;
}
}
[XmlIgnore]
public bool Shared
{
get { return xmlShared; }
set
{
xmlShared = value;
xmlExclusive = !value;
}
}
}
Which I expect to turn only into:
<a:lockscope>
<a:exclusive />
</a:lockscope>
or
<a:lockscope>
<a:shared />
</a:lockscope>
nothing else.
If you were referencing the deserializer part, I meant that if
<a:lockscope>
<a:shared />
<b:unknownproperty>
</a:lockscope>
comes to the deserialization, the unknownproperty will be just ignored.
jeff_akbm
Well I'm afraid this gives me only a little control of the resulting xml and no chance to work with this struct like with XmlElement (or XmlDocumentFragment), which it actually is.
Maybe I wrote too simple case, let's for example have a boolean property, which -when set- creates and includes a XmlElement child when "serializing".
To be concrete, real-world situation: the definition of my struct in xml is <!ELEMENT lock (scope, readonly , timeout , id+) >
I wanted to have some kind of friendly wrapper, eg. to have scope defined in enum, readonly as boolean, timeout as TimeSpan, id as List<Guid>... and so on...
using underlaying xml store like:
TimeOut {
set {
if (value == null) this.RemoveElement("timeout");
if (this.Elements["timeout"] == null) this.CreateElement("timeout");
if (value == TimeSpan.MaxValue) this.Elements["timeout"].Value = "infinity";
else this.Elements["timeout"].Value = "Second-" + value.TotalSeconds;
}
}
...but I cannot find any way how to implement it like this.
Gregory_N
Jayden CHan
Hi miloush!
for your first question: Essentially! if you don't need to do anything with the value than store it, using fields or properties is not difference
except for performance, :),the fields would more fine capability, because property access throught set or get accessor;
but if we do something like validing,transforming et...,we using properpty .:),
as your requirement, you will transform string timeout field to TimeSpan Property , so using the property to do it;
for the second question: you can't apply the XmlElement Attribute to the class, but Applying XmlElement to the property or
field is not necessary yet, XmlSerialize the fields which is public and properties which have set and get accessor. it mean
that the field or property will be readwrite.,if you don't apply XmlElementAttriubte to them,XmlSerialize will serialize them by their name,
using XmlElementAttribute you can rename XmlElement Name in Serialized xmldocument.
hope this will help you something.
good luck.
udotan
You need to use System.Xml.Serialization.
using System.Xml.Serialization;
using System.IO;
[Serializable]
public struct MyStruct
{
public string MyProp1;
public string MyProp2;
}
MyStruct mystruct = new MyStruct();
mystruct.MyProp1 = "property1";
mystruct.MyProp1 = "property2";
FileStream filestream = new FileStream("output.xml", FileMode.Create, FileAccess.ReadWrite);
XMLSerializer serializer = new XmlSerializer(typeof(MyStruct));
serializer.Serialize(filestream, mystruct);
You can also use the Deserialize method to create an instance of MyStruct from Xml.
BinaryWave
If below xml segment
<a:lockscope>
<a:shared />
<b:unknownproperty>
</a:lockscope>
comes to the deserialization, and if there is not a unknownproperty property mapping in deserializating class will be ignored auto. and above you show ,
it always be
<a:lockscope>
<a:exclusive />
<a:shared />
</a:lockscope>
exculsive and shared element will together ever i expect.