2

Question

Given a serializeable Class with lots of Properties to serialize, I want some of them to be an Attribute of an another one.

Sample

Serialize a Class like that

[Serializeable]
public class MySerializeableClass {

    public string AnyPath { get; set; }

    public bool IsActive { get; set; }

}

The result would be

<MySerializeableClass>
    <AnyPath>C:\</AnyPath>
    <IsActive>true</IsActive>
</MySerializeableClass>

But it should be

<MySerializeableClass>
    <AnyPath IsActive="true">C:\</AnyPath>
</MySerializeableClass>

Requirements

I have read here that I could achieve that by creating some (propably generic) classes. This would induce lots of extra Code, especially because there's no recognizeable order in the serialisation Structure (it's a defined standard). Means that making it generic would making it even more complicated than in the above added link - that's why I want to avoid this and why I came here.

So in general i am looking for a solution using attributes. But I am also open to other possible solutions.

EDIT:

Just to clarify, I already knew the possibility of creating classes to solve this problem. I posed this Question because I want to avoid that and I don't know how.

Community
  • 1
  • 1
LuckyLikey
  • 3,504
  • 1
  • 31
  • 54
  • possible duplicate of [Serialize Property as Xml Attribute in Element](http://stackoverflow.com/questions/11330643/serialize-property-as-xml-attribute-in-element) – Alexey Nis May 28 '15 at 06:58

2 Answers2

7

You can do it with some other class:

public class MyPathClass
{
    [XmlAttribute]
    public bool IsActive { get; set; }

    [XmlText]
    public string Value { get; set; }

    public static implicit operator string(MyPathClass value)
    {
        return value.Value;
    }

    public static implicit operator MyPathClass(string value)
    {
        return new MyPathClass { Value = value };
    }
}

public class MySerializeableClass
{
    [XmlElement]
    public MyPathClass AnyPath { get;set; }
}

Usage:

MySerializeableClass item = new MySerializeableClass() { AnyPath = "some path" };

XML:

<?xml version="1.0"?>
<MySerializeableClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <AnyPath IsActive="false">some path</AnyPath>
</MySerializeableClass>

Get path (with automatic conversion to string):

string path = item.AnyPath; // path="some path"
General-Doomer
  • 2,681
  • 13
  • 13
  • Its a cool idea... also how you route the inside value.. the point is that i want to avoid solutions using seperate classes. – LuckyLikey May 28 '15 at 07:07
  • @LuckyLikey You can create a property typed as boolean called IsActive that you just exclude from serialization and in that property just `return AnyPath.IsActive` – Georg May 28 '15 at 07:09
  • @Georg Yes I know, but imagine If I did this to every property I want to have as an attribute. It'd inflate my code pretty much. – LuckyLikey May 28 '15 at 07:13
  • @LuckyLikey : so what if there are more classes than you thought ? Are you paid more if there are less lines of code ? – thomasb May 28 '15 at 07:15
  • @cosmo0 nope. but code is loved for it's simplicity. – LuckyLikey May 28 '15 at 07:21
  • Simplicity does not mean less code. It means it's easier to understand. Sometimes it's with less code, sometimes it's with more. – thomasb May 28 '15 at 07:55
1

Another solution (with IXmlSerializable)

public class MySerializeableClass : IXmlSerializable
{
    public bool IsActive { get; set; }

    public string AnyPath { get; set; }

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        reader.Read();
        if (reader.Name == "AnyPath")
        {
            if (reader.HasAttributes)
            {
                this.IsActive = string.Equals(reader.GetAttribute("IsActive"), "true", StringComparison.InvariantCultureIgnoreCase);
            }
            this.AnyPath = reader.ReadElementContentAsString();
            reader.ReadEndElement();
        }
        else
        {
            throw new FormatException();
        }
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteStartElement("AnyPath");
        writer.WriteAttributeString("IsActive", IsActive ? "true" : "false");
        writer.WriteString(AnyPath);
        writer.WriteEndElement();
    }
}
General-Doomer
  • 2,681
  • 13
  • 13
  • That's cool. Would I now have to Implement this for all my Properties even if I don't want any special behavior or can I leave them just attributed as `[XmlAttribute]` for example and the XmlSerializer will still do them right? – LuckyLikey May 28 '15 at 07:25
  • 1
    `IXmlSerializable` is your own implementation of serialization, therefore you have to write all nodes manually. Universal solution is not exists. – General-Doomer May 28 '15 at 07:28