我有一个xsd架构,其中包含minOccurs=0
类型的可选元素(maxOccurs=1
,int
)。元素未定义为可为空。在数据模型中,我想将其映射到.net类型Nullable<int>
的字段,其中null
值应对应于xml中省略的元素。
但是,使用XmlSerializer
,似乎我 在数据模型中使用[XmlElement IsNullable=true]
声明可以为空的字段。如果我设置IsNullable=false
,我会得到异常“对于Nullable类型,IsNullable可能不会设置为'false'。”对于Nullable类型,IsNullable可能不会设置为'false'。考虑使用'System.Int32'类型或从XmlElement属性中删除IsNullable属性。“但如果我理解正确,设置IsNullable=true
(或保留属性)隐式将元素设置为nillable,从而改变了架构。
这是架构优先设计,所以我不能只为架构中的元素添加'nillable'。
如何将可为空的.net类型映射到不可为空的xml元素?
(我知道在使用数据模型中的XxxSpecified属性序列化到xml时我可以省略nil-elements,但是据我所知,这种方法仍然需要添加nsble到xsd模式。)
修改:感谢您的评论,我现在更好地理解了这个问题。实际上有两个不同的问题:
xsd.exe之类的架构代码生成器会创建一个不可为空的代码 如果架构元素不可为空,则键入生成的模型 (即使它是可选的)。我可以覆盖它(使用任何已知的代码 生成器)所以我在生成的代码中得到了可空类型?
XmlSerializer需要数据模型中的可空类型
[XmlElement IsNullable=true]
,这意味着模型隐式添加
'nillable'到架构。我可以避免这个吗?
答案 0 :(得分:5)
前段时间我也遇到过这个问题。我通过引入处理序列化逻辑的附加属性来解决它。
首先,使用[XmlIgnore]属性标记原始属性,使其从序列化/反序列化中排除。
// Mark your original property from serialization/deserialization logic
[XmlIgnore]
public int? OriginalProperty { get; set; }
然后添加附加属性并使用[XmlElement(“YourElementName”)]属性标记它以处理序列化逻辑。
// Move serialization logic to additional string property
[XmlElement("OriginalPropertyXmlElement")]
public string OriginalPropertyAsString
{
get
{
//...
}
set
{
//...
}
}
在反序列化时,它将:
set
{
// Check the field existence in xml
if (string.IsNullOrEmpty(value))
{
// Set the original property to null
this.OriginalProperty = default(int?);
}
else
{
// Get value from xml field
this.OriginalProperty = int.Parse(value);
}
}
序列化:
get
{
if (this.OriginalProperty.HasValue)
{
// Serialize it
return this.OriginalProperty.ToString();
}
else
{
// Don't serialize it
return null;
}
}
示例可能如下所示:
[XmlRoot("scene")]
public class Scene
{
[XmlIgnore]
public int? ParentId { get; set; }
[XmlElement("parent_id")]
public string ParentIdAsString
{
get
{
return this.ParentId.HasValue ? this.ParentId.ToString() : null;
}
set
{
this.ParentId = !string.IsNullOrEmpty(value) ? int.Parse(value) : default(int?);
}
}
}
这很简单,您不必编写自己的序列化程序,也不必破解xsd或其他东西。
答案 1 :(得分:2)
我不确定XxxSpecified,但您可以使用ShouldSerializeXxx方法。无论属性类型是否可为空,这些都很愉快。以下应该做的工作:
public int? Property { get ; set ; }
// this member is used for XML serialization
public bool ShouldSerializeProperty () { return Property.HasValue ; }
至于从XSD架构生成代码,如果您使用的是Microsoft的xsd.exe工具,最好的选择似乎是对生成的程序集进行后处理,例如: Mono.Cecil用于修改感兴趣的属性的类型,并插入任何额外的序列化相关成员,如ShouldSerializeXxx
。添加XSLT预处理步骤以在具有可枚举元素声明的“固定”模式上运行xsd.exe实现了第一个目标,但不是第二个目标。 xsd.exe不够灵活,无法做到你想要的。您也可以尝试将此功能添加到xsd2code,因为它是开源的。