C# Xml 序列化与“真”和“假”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1155227/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Xml Serialization vs. "True" and "False"
提问by shannon.stewart
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 capitalized (True
, False
). When I try to deserialize the XML, I'm getting a
我在使用布尔值反序列化 XML 文件时遇到问题。我正在反序列化的源 XML 文件是从 VB6 应用程序创建的,其中所有布尔值都大写 ( True
, False
)。当我尝试反序列化 XML 时,我得到一个
System.FormatException: The string 'False' is not a valid Boolean value.
Is there a way to say ignore case with an attribute?
有没有办法用属性说忽略大小写?
采纳答案by Shiraz Bhaiji
You could read that value as a string into a string field, then have a readonly bool field that had an if statement in it to return bool true or false.
您可以将该值作为字符串读入字符串字段,然后有一个只读 bool 字段,其中包含一个 if 语句以返回 bool true 或 false。
For example (using c#):
例如(使用 c#):
public bool str2bool(string str)
{
if (str.Trim().ToUpper() == "TRUE")
return true;
else
return false;
}
And you can use it in the template:
您可以在模板中使用它:
<xsl:if test="user:str2bool($mystr)">
回答by SwDevMan81
I dont think there is. You could make it string and do a comparison (String.Compare)by setting the ignoreCase value to true.
我不认为有。您可以将其设置为字符串并通过将 ignoreCase 值设置为 true 来进行比较(String.Compare)。
回答by John Saunders
There isn't. The XML Serializer works with XML Schema, and "True" and "False" are not valid booleans.
没有。XML Serializer 与 XML Schema 一起使用,并且“True”和“False”不是有效的布尔值。
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.
您可以使用 XML 转换来转换这两个值,也可以实现 IXmlSerializable 接口并自行执行序列化和反序列化。
回答by Raja Chandrasekaran
Instead of using True or False, use 0 or 1. It will work for Boolean.
不要使用 True 或 False,而是使用 0 或 1。它适用于布尔值。
回答by jeoffman
Based on another stack overflow questionyou 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);
}
}
}
回答by this.myself
I stumbled upon the same issue, and based on the answer by jman, I solved it this way:
我偶然发现了同样的问题,根据 jman 的回答,我是这样解决的:
[XmlIgnore]
public bool BadBoolField { get; set; }
[XmlAttribute("badBoolField")]
public string BadBoolFieldSerializable
{
get
{
return this.BadBoolField.ToString();
}
set
{
this.BadBoolField= Convert.ToBoolean(value);
}
}
Be aware this is not necessarily by XML / Serialization specification, but it works good and it can handle a widespread conversion values (i.e. string like "True", "true", if you would replace the constraint of being a string it could handle numbers as well).
请注意,这不一定是 XML / 序列化规范,但它运行良好,并且可以处理广泛的转换值(即像“True”、“true”这样的字符串,如果您要替换作为字符串的约束,它可以处理数字同样)。
回答by Kendall Bennett
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:
这是我根据我发现的其他一些问题提出的更简洁的解决方案。它更简洁,因为除了将类型声明为 SafeBool 之外,您不需要在代码中进行任何操作,如下所示:
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).
你甚至可以让它们成为可选的,这一切都正常。这个 SafeBool 结构将处理 true/false、yes/no 或 y/n 的任何情况变体。它总是会序列化为真/假,但是我有其他与此类似的结构,当架构需要时,我会专门将其序列化为 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;
/// <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");
}
}
}
回答by ATL_DEV
Don't bother fixing a broken xml system or fighting XmlSerializer, especially for something so trivial. It's not worth it. VB6 isn't coming back anytime soon.
不要费心修复损坏的 xml 系统或与 XmlSerializer 作斗争,尤其是对于如此微不足道的事情。这不值得。VB6 不会很快回来。
Instead, get hold of the document before it's deserialized and change the values. If you're worried about changing them outside the tags, then use regular expressions or include the angle brackets in the values.
相反,在反序列化之前获取文档并更改值。如果您担心在标签外更改它们,请使用正则表达式或在值中包含尖括号。
xml = xml.Replace("True", "true").Replace("False", "false");
It's not going to win any awards for elegance, but it gets you back to work. Sometimes you just have to blue collar it.
它不会因为优雅而赢得任何奖项,但它会让你重新开始工作。有时你只需要蓝领它。
As for performance, yes, you are reiterating through the string O(n), but since the replacement strings are the same length, it doesn't require any moving string elements around. Moreover, depending on the implementation, there might be a greater overhead in modifying XmlSerializer.
至于性能,是的,您正在重复字符串 O(n),但由于替换字符串的长度相同,因此不需要任何移动的字符串元素。此外,根据实现,修改 XmlSerializer 可能会有更大的开销。
回答by oliver
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.
我今天遇到了类似的问题,外部给定的 XML 文件包含值 TRUE/FALSE,这些值应该具有布尔含义。
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):
如果反序列化的文档包含原生 bool 对一个人的应用程序来说不是强制性的,而只是将其反序列化为限制为任何两个替代值的东西,那么人们可以简单地使用枚举(这里以 Attribute 为例) ):
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.
我认为可以通过定义隐式转换来处理这个问题,但我没有测试它,因为我不需要它。
回答by ewolfman
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:
我有一个包含许多布尔值的 xml,我不想最终有这么多重复的布尔属性,所以我尝试了一种不同的方法来提供自定义 xml 阅读器来完成这项工作:
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);
}