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

Gre*_*opp 6 c# xml xsd

我有一组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)

dbc*_*dbc 7

什么该模式说的是,如果一些外类型包含类型的元素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)


Gre*_*opp 5

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

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数组上设置/创建适当的成员,并且我可以将其用于实现此模式的多个类。