假设我有针对架构验证的XML文件。此外,我有一个可以序列化到xml以上的模型,并根据XSD架构进行验证。
在应用程序生命周期中,我的模型可以更改,因此它的XSD版本更改。
E.g。版本1.0 有元素:
<xs:complexType name="SomeConfig">
<xs:all>
<xs:element minOccurs="1" maxOccurs="1" name="ElementAlwaysValid" type="xs:boolean" />
<xs:element minOccurs="0" maxOccurs="1" name="SomeElement" type="xs:string" />
</xs:all>
</xs:complexType>
然后在版本1.1中发现有人认为它是这样的:
<xs:complexType name="SomeConfig">
<xs:all>
<xs:element minOccurs="1" maxOccurs="1" name="ElementAlwaysValid" type="xs:boolean" />
<xs:element minOccurs="1" nillable="true" name="SomeElement" type="xs:string" />
</xs:all>
</xs:complexType>
然后在版本1.2中决定:不再需要someElement。
<xs:complexType name="SomeConfig">
<xs:all>
<xs:element minOccurs="1" maxOccurs="1" name="ElementAlwaysValid"
</xs:all>
</xs:complexType>
这里有兼容性问题。
一旦出现验证错误,架构需要元素&#34; SomeElement&#34;但它不存在。
另一次可能发生错误,架构不需要SomeElement但它存在。
有没有什么好的模式可以解决这些兼容的问题?
我考虑过转换器或XSLT,但也许有一些关于这个主题的好习惯。
答案 0 :(得分:0)
例如,使用此常量类:
namespace Q32345998_XsdVersion
{
public static class Constants
{
public const string XsdNamespace = "http://tempuri.org/XMLSchema10.xsd";
public const string SomeConfigRootName = "sc";
}
}
您可以根据版本将对象拆分为不同的命名空间。每个SomeConfig
类都将使用以下属性进行修饰:
[Serializable]
[XmlType(Namespace = Constants.XsdNamespace)]
[XmlRoot(Constants.SomeConfigRootName, Namespace = Constants.XsdNamespace, IsNullable = false)]
然后通过显式/隐式转换运算符添加后向/前向合规性。因此:
namespace Q32345998_XsdVersion.v10
{
public partial class SomeConfig
{
public bool ElementAlwaysValid { get; set; }
public string SomeElement { get; set; }
}
}
namespace Q32345998_XsdVersion.v11
{
public partial class SomeConfig
{
public bool ElementAlwaysValid { get; set; }
[XmlElement(IsNullable = true)]
public string SomeElement { get; set; }
public static explicit operator v10.SomeConfig(v11.SomeConfig v11)
{
return new v10.SomeConfig() { ElementAlwaysValid = v11.ElementAlwaysValid, SomeElement = v11.SomeElement };
}
}
}
namespace Q32345998_XsdVersion.v12
{
public partial class SomeConfig
{
public bool ElementAlwaysValid { get; set; }
public static explicit operator v11.SomeConfig (v12.SomeConfig v12)
{
return new v11.SomeConfig() { ElementAlwaysValid = v12.ElementAlwaysValid, SomeElement = null };
}
public static explicit operator v10.SomeConfig(v12.SomeConfig v12)
{
return new v10.SomeConfig() { ElementAlwaysValid = v12.ElementAlwaysValid, SomeElement = null };
}
}
}
使用它:
// convert from v1.2 to v1.1 and 1.0
v12.SomeConfig sc12 = new v12.SomeConfig() { ElementAlwaysValid = true };
v11.SomeConfig sc11 = (v11.SomeConfig)sc12;
v10.SomeConfig sc10 = (v10.SomeConfig)sc12;
// convert from v1.1 to 1.0
sc11 = new v11.SomeConfig() { ElementAlwaysValid = true, SomeElement=string.Empty };
sc10 = (v10.SomeConfig)sc11;
虽然我认为对xsd和序列化对象进行版本设置会更优雅,或者在SomeConfig中添加一个版本属性。