Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get XmlSerializer to encode bools as yes/no?

I'm sending xml to another program, which expects boolean flags as "yes" or "no", rather than "true" or "false".

I have a class defined like:

[XmlRoot()]
public class Foo {
    public bool Bar { get; set; }
}

When I serialize it, my output looks like this:

<Foo><Bar>true</Bar></Foo>

But I would like it to be this:

<Foo><Bar>yes</Bar></Foo>

Can I do this at the time of serialization? I would prefer not to have to resort to this:

[XmlRoot()]
public class Foo {
    [XmlIgnore()]
    public bool Bar { get; set; }

    [XmlElement("Bar")]
    public string BarXml { get { return (Bar) ? "yes" : "no"; } }
}

Note that I also want to be able to deserialize this data back again.

like image 975
Blorgbeard Avatar asked Mar 09 '09 05:03

Blorgbeard


People also ask

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.

Can I make XmlSerializer ignore the namespace on Deserialization?

Yes, you can tell the XmlSerializer to ignore namespaces during de-serialization.

Is XmlSerializer thread safe?

Since XmlSerializer is one of the few thread safe classes in the framework you really only need a single instance of each serializer even in a multithreaded application. The only thing left for you to do, is to devise a way to always retrieve the same instance.


1 Answers

Ok, I've been looking into this some more. Here's what I've come up with:

// use this instead of a bool, and it will serialize to "yes" or "no"
// minimal example, not very robust
public struct YesNo : IXmlSerializable {

    // we're just wrapping a bool
    private bool Value;

    // allow implicit casts to/from bool
    public static implicit operator bool(YesNo yn) {
        return yn.Value;
    }
    public static implicit operator YesNo(bool b) {
        return new YesNo() {Value = b};
    }

    // implement IXmlSerializable
    public XmlSchema GetSchema() { return null; }
    public void ReadXml(XmlReader reader) {
        Value = (reader.ReadElementContentAsString() == "yes");
    }
    public void WriteXml(XmlWriter writer) {
        writer.WriteString((Value) ? "yes" : "no");
    }
}

Then I change my Foo class to this:

[XmlRoot()]
public class Foo {      
    public YesNo Bar { get; set; }
}

Note that because YesNo is implicitly castable to bool (and vice versa), you can still do this:

Foo foo = new Foo() { Bar = true; };
if ( foo.Bar ) {
   // ... etc

In other words, you can treat it like a bool.

And w00t! It serializes to this:

<Foo><Bar>yes</Bar></Foo>

It also deserializes correctly.

There is probably some way to get my XmlSerializer to automatically cast any bools it encounters to YesNos as it goes - but I haven't found it yet. Anyone?

like image 75
Blorgbeard Avatar answered Sep 27 '22 00:09

Blorgbeard