Xml Serialization vs. “True” and “False”

前端 未结 10 979
傲寒
傲寒 2021-01-07 20:23

I\'m having an issue with deserializing an XML file with boolean values. The source XML files I\'m deserializing were created from a VB6 app, where all boolean values are c

相关标签:
10条回答
  • 2021-01-07 20:26

    I dont think there is. You could make it string and do a comparison (String.Compare) by setting the ignoreCase value to true.

    0 讨论(0)
  • 2021-01-07 20:30

    Based on another stack overflow question you can do:

    public class MySerilizedObject
    {
        [XmlIgnore]
        public bool BadBoolField { get; set; }
    
        [XmlElement("BadBoolField")]
        public string BadBoolFieldSerialize
        {
            get { return this.BadBoolField ? "True" : "False"; }
            set
            {
                if(value.Equals("True"))
                    this.BadBoolField = true;
                else if(value.Equals("False"))
                    this.BadBoolField = false;
                else
                    this.BadBoolField = XmlConvert.ToBoolean(value);
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-07 20:30

    I have an xml with many booleans and I didn't want to end up having so many duplicate boolean properties, so I tried a different approach of providing a custom xml reader to do the work:

    public class MyXmlReader : XmlTextReader
    {
        public MyXmlReader(TextReader reader) : base(reader) { }
        public override string ReadElementString()
        {
            var text = base.ReadElementString();
    
            // bool TryParse accepts case-insensitive 'true' and 'false'
            if (bool.TryParse(text, out bool result))
            {
                text = XmlConvert.ToString(result);
            }
    
            return text;
        }
    }
    

    and use with:

    using (var sr = new StringReader(text))
    using (var r = new MyXmlReader(sr))
    {
        var result = serializer.Deserialize(r);
    }
    
    0 讨论(0)
  • 2021-01-07 20:31

    Here is a much cleaner solution I came up with based on some other questions I found. It is much cleaner because then you don't need to anything in your code except declare the type as SafeBool, like this:

    public class MyXMLClass
    {
        public SafeBool Bool { get; set; }
        public SafeBool? OptionalBool { get; set; }
    }
    

    you can even make them optional and it all just works. This SafeBool struct will handle any case variants of true/false, yes/no or y/n. It will always serialize as true/false, however I have other structs similar to this I use to serialize specifically as y/n or yes/no when the schema requires that (ie: BoolYN, BoolYesNo structs).

    using System.Xml;
    using System.Xml.Schema;
    using System.Xml.Serialization;
    
    namespace AMain.CommonScaffold
    {
        public struct SafeBool : IXmlSerializable
        {
            private bool _value;
    
            /// <summary>
            /// Allow implicit cast to a real bool
            /// </summary>
            /// <param name="yn">Value to cast to bool</param>
            public static implicit operator bool(
                SafeBool yn)
            {
                return yn._value;
            }
    
            /// <summary>
            /// Allow implicit cast from a real bool
            /// </summary>
            /// <param name="b">Value to cash to y/n</param>
            public static implicit operator SafeBool(
                bool b)
            {
                return new SafeBool { _value = b };
            }
    
            /// <summary>
            /// This is not used
            /// </summary>
            public XmlSchema GetSchema()
            {
                return null;
            }
    
            /// <summary>
            /// Reads a value from XML
            /// </summary>
            /// <param name="reader">XML reader to read</param>
            public void ReadXml(
                XmlReader reader)
            {
                var s = reader.ReadElementContentAsString().ToLowerInvariant();
                _value = s == "true" || s == "yes" || s == "y";
            }
    
            /// <summary>
            /// Writes the value to XML
            /// </summary>
            /// <param name="writer">XML writer to write to</param>
            public void WriteXml(
                XmlWriter writer)
            {
                writer.WriteString(_value ? "true" : "false");
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-07 20:31

    There isn't. The XML Serializer works with XML Schema, and "True" and "False" are not valid booleans.

    You could either use an XML Transform to convert these two values, or you could implement the IXmlSerializable interface and do the serialization and deserialization on your own.

    0 讨论(0)
  • 2021-01-07 20:31

    There is an incredibly simple and short solution in a special case.

    I have encountered a similar problem today, with an externally given XML file that contains the values TRUE/FALSE which are supposed to have boolean meaning.

    If it is not mandatory for one's application that the deserialized document contains a native bool, but it's merely about deserializing it to something that is constrained to any two alternative values, then one can simply use an enum (here for an Attribute by way of example):

    public enum BOOL {FALSE, TRUE};
    
    public MyClass
    {
        [XmlAttribute]
        public BOOL MyStrangeBooleanAttribute {get; set;}
    }
    

    This will just deserialize without any problem from an Element like this

    <MyClass MyStrangeBooleanAttribute = "TRUE" />
    

    Of course it is not possible then to use the property in code for direct boolean operations, like

    if (MyStrangeBooleanAttribute) // ... doesn't work
    

    I think it could probably be possible to handle this by defining an implicit conversion, but I haven't tested it because I don't need it.

    0 讨论(0)
提交回复
热议问题