我有一组XML模式文件提供给我.我无法更改XML,因为这些有时会更新.我正在使用xsd.exe将架构文件转换为生成的c#代码.我不能使用任何第三方工具.其中一个XML模式文件的一部分显示如下:
<xs:complexType name="LocationType">
<xs:choice minOccurs="1" maxOccurs="1">
<xs:element name="LocNum" minOccurs="1" maxOccurs="1" type="xs:string" />
<xs:sequence>
<xs:element name="Name" minOccurs="0" maxOccurs="1" type="xs:string" />
<xs:element name="Address" minOccurs="0" maxOccurs="1" type="xs:string" />
<xs:element name="City" minOccurs="1" maxOccurs="1" type="xs:string" />
<xs:element name="State" minOccurs="0" maxOccurs="1">
</xs:sequence>
</xs:choice>
</xs:complexType>
Run Code Online (Sandbox Code Playgroud)
当转换为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;
/// <remarks/>
[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; }
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("ItemsElementName")]
[System.Xml.Serialization.XmlIgnoreAttribute()]
public ItemsChoiceType[] ItemsElementName
{
get { return this.itemsElementNameField; }
set { this.itemsElementNameField = value; }
}
}
Run Code Online (Sandbox Code Playgroud)
由于这些都生成了部分类,我可以自由添加其他代码.我需要能够读取/设置各个属性,例如姓名,地址,城市等.
我需要能够序列化这些对象以匹配模式.
在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
}
}
}
Run Code Online (Sandbox Code Playgroud)
什么该模式说的是,如果一些外类型包含类型的元素LocationType,一个希望找到里面要么
1)子元素<LocNum>OR
2)在序列这些子元素:<Name>,<Address>,<City>和<State>.
因此,这里的数据是多态的,即使它没有在xsd.exe生成的c#类中明确建模.这种情况很有意义 - 可以明确指定位置,也可以间接指定为表中的查找.
在对这样的多态序列进行反序列化时,XmlSerializer将它找到的每个元素放在与序列中的元素对应的数组字段中,在本例中为数组Items.此外,XmlChoiceIdentifierAttribute在这种情况下,应该存在由属性标识的另一个对应的阵列字段ItemsElementName.此阵列中的条目必须与Items阵列1-1对应.它Items通过ItemsChoiceType枚举记录在数组的每个索引中反序列化的元素的名称,其枚举名称必须与XmlElementAttribute装饰Items数组的属性中的名称匹配.这允许已知多态数据的特定选择.
因此,为了完善您的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<object> newItems = new List<object>();
List<ItemsChoiceType> newItemsElementName = new List<ItemsChoiceType>();
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<TIDentifier, TResult>(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];
}
}
Run Code Online (Sandbox Code Playgroud)
这是我从原始答案中学到的最终解决方案。该静态类用于获取和设置适当的属性。
public static class XmlPolymorphicArrayHelper
{
public static TResult GetItem<TIDentifier, TResult>(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<TIDentifier, TResult>(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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后从部分类中调用它们,如下所示:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这将在Items数组上设置/创建适当的成员,并且我可以将其用于实现此模式的多个类。
| 归档时间: |
|
| 查看次数: |
3578 次 |
| 最近记录: |