1

I have some entities that were generated from a database and I wanted to serialize them to XML. The problem is that some of the entities have column names that are not so user friendly and this is reflected in the fields of the generated entity.

Is there a C# attribute that I could apply to the class fields so that I could add an xml attribute, that contains a friendly-name value, to the xml element itself? For example, using something similar to the XmlAttribute:

public class Book
{
    public string Title { get; set; }

    [XmlAttribute("friendlyName","International Standard Book Number")]
    public string ISBN { get; set; }
} 

Should result in something like this when it is serialized:

<Book>
  <Title>To Kill a Mockingbird</Title>
  <ISBN friendlyName="International Standard Book Number">9780061120084</ISBN>
</Book>

2 Answers 2

1

There is not an attribute that will do that. Its not common to mix element documentation with the xml data. Usually, you want to document your xml schema with an xsd document or some other means.

That being said, here is how you could do it. You'd need to change the ISBN property from a string to a custom type that has a friendlyName property that you can serialize.

public class Book
{
    public string Title { get; set; }

    public ISBN ISBN { get; set; }
}

public class ISBN
{
    [XmlText]
    public string value { get; set; }

    [XmlAttribute]
    public string friendlyName { get; set; }
}

The following will serialize exactly like what you have in your question.

Book b = new Book
{
    Title = "To Kill a Mockingbird",
    ISBN = new ISBN
    {
        value = "9780061120084",
        friendlyName = "International Standard Book Number",
    }
};

UPDATE

OK, another approach would be to create a custom XmlWriter that can intercept calls made by the serializer to create elements. When an element is being created for an property that you want to add a friendly name to, you can write in your own custom attribute.

public class MyXmlTextWriter : XmlTextWriter
{
    public MyXmlTextWriter(TextWriter w)
        : base(w)
    {
    }

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        base.WriteStartElement(prefix, localName, ns);

        switch(localName)
        {
            case "ISBN":
                WriteAttributeString("friendlyName", "International Standard Book Number");
                break;
        }
    }
}

Here is an example of how you would use it (from a console app):

XmlSerializer serializer = new XmlSerializer(typeof(Book));
serializer.Serialize(new MyXmlTextWriter(Console.Out), b);

You can implement the other constructors of XmlTextWriter, if you need to be able to write to other things like a Stream.

Sign up to request clarification or add additional context in comments.

4 Comments

I just foresee too much work in pulling out the property into a custom type as there are many class fields that I need to deal with. Now I'm wondering if there is a way to write a custom C# attribute or extend an existing one to do this?
Thanks. Another issue though is that I have to deal with several entities. Is there a way where I can modify the code to only write out the attribute if it belongs to a particular entity? I don't want to conflict with other entities that could potentially have the same field name but has a different meaning.
If you have xml where there are elements with the same names, but different meanings, then those elements should be in distinct xml namespaces. You could add the namespace or the namespace prefix to your element matching logic using the ns and prefix arguments to WriteStartElement(). If you don't have proper namespaces, then you could do something more complicated like keep track of what an elements parents are using a Stack -- push on WriteStartElement() pop on WriteEndElement().
Attributes are intended for metadata, regardless of whether they are documentation or not. I don't like being forced to create a new class, but at least that's an option, but only when I have access to the code for the class.
0

Try this

    [XmlRoot("Book")]
    public class Book
    {
        [XmlElement("Title")]
        public string Title { get; set; }

        [XmlElement("ISBN")]
        public ISBN isbn { get; set; }
    }
    [XmlRoot("ISBN")]
    public class ISBN
    {
        [XmlAttribute("friendlyName")]
        public string friendlyName { get; set; }

        [XmlText]
        public string value { get; set; }
    }​

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.