Xml序列化与“真”和“假”

我遇到了使用布尔值反序列化XML文件的问题。 我正在反序列化的源XML文件是从VB6应用程序创建的,其中所有布尔值都是大写的( TrueFalse )。 当我尝试反序列化XML时,我得到了一个

 System.FormatException: The string 'False' is not a valid Boolean value. 

有没有办法说用属性忽略大小写?

您可以将该值作为字符串读入字符串字段,然后使用readonly bool字段,其中包含if语句以返回bool true或false。

例如(使用c#):

 public bool str2bool(string str) { if (str.Trim().ToUpper() == "TRUE") return true; else return false; } 

你可以在模板中使用它:

  

而不是使用True或False,使用0或1.它将适用于布尔值。

基于另一个堆栈溢出问题,您可以执行:

 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); } } } 

没有。 XML Serializer使用XML Schema,“True”和“False”不是有效的布尔值。

您可以使用XML转换来转换这两个值,也可以实现IXmlSerializable接口并自行执行序列化和反序列化。

我不认为有。 您可以通过将ignoreCase值设置为true来使其成为字符串并进行比较(String.Compare) 。

我偶然发现同样的问题,根据jman的回答,我这样解决了:

  [XmlIgnore] public bool BadBoolField { get; set; } [XmlAttribute("badBoolField")] public string BadBoolFieldSerializable { get { return this.BadBoolField.ToString(); } set { this.BadBoolField= Convert.ToBoolean(value); } } 

请注意,这不一定是XML /序列化规范,但它运行良好,它可以处理广泛的转换值(即字符串如“True”,“true”,如果你要替换它可以处理数字的字符串的约束以及)。

根据我发现的其他一些问题,我提出了一个更清洁的解决方案。 它更清晰,因为除了将类型声明为SafeBool之外,您不需要代码中的任何内容,如下所示:

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

你甚至可以让它们成为可选的,一切正常。 此SafeBool结构将处理true / false,yes / no或y / n的任何case变体。 它总是序列化为true / false,但是我有其他类似的结构,我用它来特定地序列化为y / n或yes / no,当架构需要时(即:BoolYN,BoolYesNo结构)。

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

在特殊情况下,有一个非常简单和简短的解决方案。

我今天遇到了类似的问题,外部给定的XML文件包含值TRUE / FALSE,它们应该具有布尔含义。

如果一个人的应用程序不强制反序列化文档包含本机bool,但它只是将其反序列化为受限于任何两个替代值的东西,那么可以简单地使用枚举(这里作为示例的属性) ):

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

这将只是反序列化,没有像这样的元素的任何问题

  

当然,不可能在代码中使用属性来进行直接布尔操作,例如

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

我认为可能通过定义隐式转换来处理这个问题,但是我没有测试它,因为我不需要它。

不要打扰修复破碎的xml系统或打击XmlSerializer,特别是对于那些微不足道的事情。 这不值得。 VB6不会很快回来。

相反,在反序列化之前获取文档并更改值。 如果您担心在标签外更改它们,请使用正则表达式或在值中包含尖括号。

  xml = xml.Replace("True", "true").Replace("False", "false"); 

它不会因为优雅而赢得任何奖项,但它会让你重新开始工作。 有时你只需要蓝领。

至于性能,是的,你通过字符串O(n)重复,但由于替换字符串的长度相同,所以它不需要任何移动的字符串元素。 此外,根据实现,修改XmlSerializer可能会有更大的开销。