Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write a comment to an XML file when using the XmlSerializer?

Tags:

I have an object Foo which I serialize to an XML stream.

public class Foo {   // The application version, NOT the file version!   public string Version {get;set;}   public string Name {get;set;} }  Foo foo = new Foo { Version = "1.0", Name = "Bar" }; XmlSerializer xmlSerializer = new XmlSerializer(foo.GetType()); 

This works fast, easy and does everything currently required.

The problem I'm having is that I need to maintain a separate documentation file with some minor remarks. As in the above example, Name is obvious, but Version is the application version and not the data file version as one could expect in this case. And I have many more similar little things I want to clarify with a comment.

I know I can do this if I manually create my XML file using the WriteComment() function, but is there a possible attribute or alternative syntax I can implement so that I can keep using the serializer functionality?

like image 964
Jensen Avatar asked Sep 12 '11 09:09

Jensen


People also ask

Which is the proper commenting method for XML?

To insert XML comments for a code element Type /// in C#, or ''' in Visual Basic.

Does XML allow commenting elements?

Allows notes and other human readable comments to be included within an XML file. XML Parsers should ignore XML comments. Some constrains govern where comments may be placed with an XML file.

How does the XmlSerializer work C#?

The XmlSerializer creates C# (. cs) files and compiles them into . dll files in the directory named by the TEMP environment variable; serialization occurs with those DLLs. These serialization assemblies can be generated in advance and signed by using the SGen.exe tool.

What is XML Deserialization?

Serialization is a process by which an object's state is transformed in some serial data format, such as XML or binary format. Deserialization, on the other hand, is used to convert the byte of data, such as XML or binary data, to object type.


1 Answers

This is possible using the default infrastructure by making use of properties that return an object of type XmlComment and marking those properties with [XmlAnyElement("SomeUniquePropertyName")].

I.e. if you add a property to Foo like this:

public class Foo {     [XmlAnyElement("VersionComment")]     public XmlComment VersionComment { get { return new XmlDocument().CreateComment("The application version, NOT the file version!"); } set { } }      public string Version { get; set; }     public string Name { get; set; } } 

The following XML will be generated:

<Foo>   <!--The application version, NOT the file version!-->   <Version>1.0</Version>   <Name>Bar</Name> </Foo> 

However, the question is asking for more than this, namely some way to look up the comment in a documentation system. The following accomplishes this by using extension methods to look up the documentation based on the reflected comment property name:

public class Foo {     [XmlAnyElement("VersionXmlComment")]     public XmlComment VersionXmlComment { get { return GetType().GetXmlComment(); } set { } }      [XmlComment("The application version, NOT the file version!")]     public string Version { get; set; }      [XmlAnyElement("NameXmlComment")]     public XmlComment NameXmlComment { get { return GetType().GetXmlComment(); } set { } }      [XmlComment("The application name, NOT the file name!")]     public string Name { get; set; } }  [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class XmlCommentAttribute : Attribute {     public XmlCommentAttribute(string value)     {         this.Value = value;     }      public string Value { get; set; } }  public static class XmlCommentExtensions {     const string XmlCommentPropertyPostfix = "XmlComment";      static XmlCommentAttribute GetXmlCommentAttribute(this Type type, string memberName)     {         var member = type.GetProperty(memberName);         if (member == null)             return null;         var attr = member.GetCustomAttribute<XmlCommentAttribute>();         return attr;     }      public static XmlComment GetXmlComment(this Type type, [CallerMemberName] string memberName = "")     {         var attr = GetXmlCommentAttribute(type, memberName);         if (attr == null)         {             if (memberName.EndsWith(XmlCommentPropertyPostfix))                 attr = GetXmlCommentAttribute(type, memberName.Substring(0, memberName.Length - XmlCommentPropertyPostfix.Length));         }         if (attr == null || string.IsNullOrEmpty(attr.Value))             return null;         return new XmlDocument().CreateComment(attr.Value);     } } 

For which the following XML is generated:

<Foo>   <!--The application version, NOT the file version!-->   <Version>1.0</Version>   <!--The application name, NOT the file name!-->   <Name>Bar</Name> </Foo> 

Notes:

  • The extension method XmlCommentExtensions.GetXmlCommentAttribute(this Type type, string memberName) assumes that the comment property will be named xxxXmlComment where xxx is the "real" property. If so, it can automatically determine the real property name by marking the incoming memberName attribute with CallerMemberNameAttribute. This can be overridden manually by passing in the real name.

  • Once the type and member name are known, the extension method looks up the relevant comment by searching for an [XmlComment] attribute applied to the property. This could be replaced with a cached lookup into a separate documentation file.

  • While it is still necessary to add the xxxXmlComment properties for each property that might be commented, this is likely to be less burdensome than implementing IXmlSerializable directly which is quite tricky, can lead to bugs in deserialization, and can require nested serialization of complex child properties.

  • To ensure that each comment precedes its associated element, see Controlling order of serialization in C#.

  • For XmlSerializer to serialize a property it must have both a getter and setter. Thus I gave the comment properties setters that do nothing.

Working .Net fiddle.

like image 106
dbc Avatar answered Oct 29 '22 18:10

dbc