xsd.exe使用数组中的多个元素生成c#

我有一组XML模式文件提供给我。 我无法更改XML,因为这些有时会更新。 我正在使用xsd.exe将架构文件转换为生成的c#代码。 我不能使用任何第三方工具。 其中一个XML模式文件的一部分显示如下:

           

当转换为c#时,我得到如下结果:

 [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://abcxyz.com")] public partial class LocationType { private object[] itemsField; private ItemsChoiceType[] itemsElementNameField; ///  [System.Xml.Serialization.XmlElementAttribute("Address", typeof(string), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] [System.Xml.Serialization.XmlElementAttribute("City", typeof(string), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] [System.Xml.Serialization.XmlElementAttribute("LocNum", typeof(string), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] [System.Xml.Serialization.XmlElementAttribute("Longitude", typeof(decimal), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] [System.Xml.Serialization.XmlElementAttribute("State", typeof(LocationTypeState), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")] public object[] Items { get { return this.itemsField; } set { this.itemsField = value; } } ///  [System.Xml.Serialization.XmlElementAttribute("ItemsElementName")] [System.Xml.Serialization.XmlIgnoreAttribute()] public ItemsChoiceType[] ItemsElementName { get { return this.itemsElementNameField; } set { this.itemsElementNameField = value; } } } 

由于这些都生成了部分类,我可以自由添加其他代码。 我需要能够读取/设置各个属性,例如姓名,地址,城市等。

我需要能够序列化这些对象以匹配架构。

在c#中有没有办法创建一个公共属性,以适当的顺序读取或设置Items数组中的值,等等? 即:

 public partial class LocationType { public string Address { get { // code here to return the correct Items[] element } set { // code here to set the correct Items[] element } } } 

该模式所说的是,如果某个外部类型包含一个类型为LocationType的元素,那么人们可能希望在其中找到

1)子元素 ,OR

2)这些子元素依次为:

因此,这里的数据是多态的,即使它没有在xsd.exe生成的c#类中明确建模。 这种情况很有意义 – 可以明确指定位置,也可以间接指定为表中的查找。

当像这样反序列化多态序列时, XmlSerializer将它找到的每个元素放在对应于序列中元素的数组字段中,在本例中是数组Items 。 此外,应该有另一个由XmlChoiceIdentifierAttribute属性标识的相应数组字段,在本例中为ItemsElementName 。 此数组中的条目必须与Items数组1-1对应。 它通过ItemsChoiceType枚举记录Items数组的每个索引中反序列化的元素的名称,其枚举名称必须与装饰Items数组的XmlElementAttribute属性中的名称匹配。 这允许已知多态数据的特定选择。

因此,为了完善LocationType类的实现,您需要确定给定的LocationType是直接还是间接; 获取各种属性; 对于每种类型(直接或间接),设置所有必需的数据。

这是原型。 (你没有在你的问题中包含LocationTypeState的定义,所以我只是将它视为一个字符串):

 public partial class LocationType { public LocationType() { } public LocationType(string locNum) { SetIndirectLocation(locNum); } public LocationType(string name, string address, string city, string state) { SetDirectLocation(name, address, city, state); } public bool IsIndirectLocation { get { return Array.IndexOf(ItemsElementName, ItemsChoiceType.LocNum) >= 0; } } public string Address { get { return (string)XmlPolymorphicArrayHelper.GetItem(Items, ItemsElementName, ItemsChoiceType.Address); } } public string LocNum { get { return (string)XmlPolymorphicArrayHelper.GetItem(Items, ItemsElementName, ItemsChoiceType.LocNum); } } // Other properties as desired. public void SetIndirectLocation(string locNum) { if (string.IsNullOrEmpty(locNum)) throw new ArgumentException(); object[] newItems = new object[] { locNum }; ItemsChoiceType [] newItemsElementName = new ItemsChoiceType [] { ItemsChoiceType.LocNum }; this.Items = newItems; this.ItemsElementName = newItemsElementName; } public void SetDirectLocation(string name, string address, string city, string state) { // In the schema, "City" is mandatory, others are optional. if (string.IsNullOrEmpty(city)) throw new ArgumentException(); List newItems = new List(); List newItemsElementName = new List(); if (name != null) { newItems.Add(name); newItemsElementName.Add(ItemsChoiceType.Name); } if (address != null) { newItems.Add(address); newItemsElementName.Add(ItemsChoiceType.Address); } newItems.Add(city); newItemsElementName.Add(ItemsChoiceType.City); if (state != null) { newItems.Add(state); newItemsElementName.Add(ItemsChoiceType.State); } this.Items = newItems.ToArray(); this.ItemsElementName = newItemsElementName.ToArray(); } } public static class XmlPolymorphicArrayHelper { public static TResult GetItem(TResult[] items, TIDentifier[] itemIdentifiers, TIDentifier itemIdentifier) { if (itemIdentifiers == null) { Debug.Assert(items == null); return default(TResult); } Debug.Assert(items.Length == itemIdentifiers.Length); var i = Array.IndexOf(itemIdentifiers, itemIdentifier); if (i < 0) return default(TResult); return items[i]; } } 

这是我们从原始答案中学到的最终解决方案。 此静态类用于获取和设置适当的属性。

 public static class XmlPolymorphicArrayHelper { public static TResult GetItem(TResult[] items, TIDentifier[] itemIdentifiers, TIDentifier itemIdentifier) { if (itemIdentifiers == null) { return default(TResult); } var i = Array.IndexOf(itemIdentifiers, itemIdentifier); return i < 0 ? default(TResult) : items[i]; } public static void SetItem(ref TResult[] items, ref TIDentifier[] itemIdentifiers, TIDentifier itemIdentifier, TResult value) { if (itemIdentifiers == null) { itemIdentifiers = new[] { itemIdentifier }; items = new[] { value }; return; } var i = Array.IndexOf(itemIdentifiers, itemIdentifier); if (i < 0) { var newItemIdentifiers = itemIdentifiers.ToList(); newItemIdentifiers.Add(itemIdentifier); itemIdentifiers = newItemIdentifiers.ToArray(); var newItems = items.ToList(); newItems.Add(value); items = newItems.ToArray(); } else { items[i] = value; } } } 

然后从部分类中调用它们,如下所示:

 public partial class LocationType { [XmlIgnore] public string Address { get { return (string)XmlPolymorphicArrayHelper.GetItem(Items, ItemsElementName, ItemsChoiceType.Address); } set { XmlPolymorphicArrayHelper.SetItem(ref this.itemsField, ref this.itemsElementNameField, ItemsChoiceType.Address, value); } } } 

这在Items数组上设置/创建了适当的成员,我可以将它用于实现此模式的多个类。