問題描述
我有一組提供給我的 XML 模式文件.我無法更改 XML,因為這些有時會更新.我正在使用 xsd.exe 將架構文件轉換為生成的 c# 代碼.我不能使用任何第三方工具.XML 模式文件之一的部分顯示如下:
I have a set of XML schema files provided to me. I cannot changed the XML as these will be updated on occasion. I am using xsd.exe to convert the schema files to generated c# code. I cannot use any third party tools. Part of one of the XML schema files appears as such:
<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>
當轉換為 c# 時,我得到如下結果:
When converted to c#, I get a result such as this:
[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; }
}
}
由于這些都生成為部分類,我可以隨意添加其他代碼.我需要能夠讀取/設置各個屬性,例如姓名、地址、城市等.
Since these all get generated to partial classes, I am free to add additional code. I need to be able to read/set the individual properties, such as Name, Address, City, etc.
我需要能夠序列化這些對象以匹配架構.
I need to be able to serialize these objects to match the schema.
在 C# 中有沒有辦法創建一個公共屬性,該屬性將以正確的順序讀取或設置 Items 數組中的值等?即:
Is there a way in c# to create a public property that will read or set the value in the Items array at the proper sequence, etc.? ie:
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
類型的元素,人們會期望在 內部找到要么
What that schema says is that if some outer type contains an element of type LocationType
, one would expect to find inside either
1) 一個子元素<LocNum>
,或
2) 這些子元素依次為:
、、
和><狀態>
.
2) These sub-elements in sequence: <Name>
, <Address>
, <City>
and <State>
.
因此,這里的數據是多態的,即使它沒有在 xsd.exe 生成的 c# 類中明確建模.這種做法是有道理的——可以顯式指定位置,也可以間接指定為在表中查找.
Thus the data here is polymorphic, even though it isn't being explicitly modeled as such in the c# classes generated by xsd.exe. This sort of makes sense -- a location might be specified explicitly, or indirectly as a look-up in a table.
當像這樣反序列化多態序列時,XmlSerializer
將它找到的每個元素放入與序列中的元素相對應的數組字段中,在本例中為數組Items
.此外,應該還有另一個對應的數組字段,由 XmlChoiceIdentifierAttribute
屬性,在本例中為 ItemsElementName
.此數組中的條目必須與 Items
數組一一對應.它通過 ItemsChoiceType
枚舉記錄在 Items
數組的每個索引中被反序列化的元素的名稱,其枚舉名稱必須與 XmlElementAttribute
屬性裝飾 Items
數組.這樣就可以知道多態數據的具體選擇.
When deserializing a polymorphic sequence like this, XmlSerializer
puts each element it finds in the array field corresponding to the elements in the sequence, in this case the array Items
. In addition, there should be another corresponding array field identified by the XmlChoiceIdentifierAttribute
attribute, in this case ItemsElementName
. The entries in this array must needs be in 1-1 correspondence with the Items
array. It records the name of the element that was deserialized in each index of the Items
array, by way of the ItemsChoiceType
enumeration, whose enum names must match the names in the XmlElementAttribute
attributes decorating the Items
array. This allows the specific choice of polymorphic data to be known.
因此,要完善 LocationType
類的實現,您需要確定給定的 LocationType
是直接的還是間接的;取出各種屬性;并為每種類型(直接或間接)設置所有必需的數據.
Thus, to round out the implementation of your LocationType
class, you will need to determine whether a given LocationType
is direct or indirect; fetch various properties out; and for each type (direct or indirect), set all required data.
這是一個原型.(您的問題中沒有包含 LocationTypeState
的定義,所以我只是將其視為字符串):
Here is a prototype of that. (You didn't include the definition for LocationTypeState
in your question, so I'm just treating it as a string):
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];
}
}
這篇關于xsd.exe 生成的 c# 具有數組中的多個元素的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!