#c# #xml #serialization
#c# #xml #сериализация
Вопрос:
У меня есть эта схема
<xs:complexType name="FatherElement">
<xs:sequence>
<xs:element ref="FatherClass"/>
<xs:choice>
<xs:sequence>
<xs:element ref="FatherType"/>
<xs:element ref="FatherLocation" minOccurs="0"/>
<xs:element ref="FatherTypeDescription" minOccurs="0"/>
</xs:sequence>
<xs:sequence>
<xs:element ref="FatherLocation"/>
<xs:element ref="FatherTypeDescription" minOccurs="0"/>
</xs:sequence>
<xs:element ref="FatherTypeDescription"/>
</xs:choice>
<xs:element ref="FatherBasis"/>
<xs:element ref="FatherRole" minOccurs="0"/>
<xs:element name="Extension" type="FatherElement_ExtensionType" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
И я пытаюсь сопоставить с этим отображением C # (было бы неплохо иметь все поля, но они мне все сейчас не нужны)
[System.Serializable()]
[System.ComponentModel.DesignerCategory("code")]
[System.Xml.Serialization.XmlType(AnonymousType = true, Namespace = "http://www.lol.com/Standards/lol/1")]
public class FatherElement
{
/// <remarks/>
public string FatherTypeDescription { get; set; }
/// <remarks/>
public string FatherType { get; set; }
/// <remarks/>
public FatherLocation FatherLocation { get; set; }
}
[System.Serializable()]
[System.ComponentModel.DesignerCategory("code")]
[System.Xml.Serialization.XmlType(AnonymousType = true, Namespace = "http://www.lol.com/Standards/lol/1")]
public class FatherLocation
{
/// <remarks/>
public FatherLocationLocation Location { get; set; }
}
[System.Serializable()]
[System.ComponentModel.DesignerCategory("code")]
[System.Xml.Serialization.XmlType(AnonymousType = true, Namespace = "http://www.lol.com/Standards/lol/1")]
public class FatherLocationLocation
{
/// <remarks/>
public string Country { get; set; }
}
Входящее значение XML, которое я получаю, является
<FatherElement>
<FatherClass>classValue</FatherClass>
<FatherType>typeValue</FatherType>
<FatherTypeDescription>typeValueDesc</FatherTypeDescription>
<FatherBasis>basisValue</FatherBasis>
<FatherRole>RoleValue</FatherRole>
</FatherElement>
И тот, который я получаю, это:
<FatherElement>
<FatherTypeDescription>typeValueDesc</FatherTypeDescription>
<FatherType>typeValue</FatherType>
</FatherElement>
Когда я пытаюсь проверить его на соответствие SDC, я получаю сообщение об ошибке, в котором говорится, что элемент FatherElement имеет недопустимое дочернее описание FatherTypeDescription.
Я попытался сгенерировать отображение C # из XSD, но генерируемый им код преобразует варианты выбора в элементы типа objects, и я бы хотел сохранить строгую типизацию.
Есть идея?
Комментарии:
1. В прошлый раз, когда я использовал XSDs для генерации классов WCF (VS2012),
<xs:choice>
элемент не поддерживался.2. Теперь это поддерживается. Когда используется элемент выбора, он создает два элемента в модели: Object Item и ItemName типа enum (где перечисление содержит доступные поля в пределах выбора)
Ответ №1:
<xs:choice>
все еще проблема при создании классов. Проблема заключается в упаковке и именовании выбранного элемента. Я бы предложил обходной путь.
Как я понял, вы хотите выбрать одну из трех возможностей:
-
У отца есть
Type
и может бытьLocation
иDescription
-
Отец имеет
Location
и можетDescription
-
У отца есть
Description
только
Проблема в том, что типы последовательностей, определенные в вашем выборе, не будут распознаны точно (как прокомментировал MaPi, вам придется использовать ItemName-Enum и Item). Вы могли бы переместить объединяемые последовательности в элемент, чтобы объяснить VS, как обрабатывать их как отдельные объекты. Вот пример (я заменил ваши сложные типы строками, чтобы получить удобный / генерируемый пример):
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="FatherElement">
<xs:complexType>
<xs:sequence>
<xs:element name="FatherClass" type="xs:string"/>
<xs:choice> <!-- In this choice we can choose 3 different elements -->
<xs:element name="CompleteFather"> <!-- 1 -->
<xs:complexType>
<xs:sequence>
<xs:element name="FatherType" type="xs:string"/>
<xs:element name="FatherLocation" type="xs:string" minOccurs="0"/>
<xs:element name="FatherTypeDescription" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="UncompletaFather"> <!-- 2 -->
<xs:complexType>
<xs:sequence>
<xs:element name="FatherLocation" type="xs:string"/>
<xs:element name="FatherTypeDescription" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="FatherTypeDescription" type="xs:string"/> <!-- 3 -->
</xs:choice>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Вот несколько примеров c #-кода.
FatherElement e = new FatherElement();
e.FatherClass = "Some Element";
// Here we choose our element in our choice. It'll be boxed into an object.
e.Item = new FatherElementCompleteFather()
{
FatherLocation = "loc",
FatherType = "type",
FatherTypeDescription = "desc"
};
string filePath = @"C:Temptest.xml";
XmlSerializer x = new XmlSerializer(e.GetType());
using (var sw = new StreamWriter(filePath))
x.Serialize(sw, e);
Комментарии:
1. Спасибо. Идея хорошая, но основная проблема заключается в том, что xsd создается третьей стороной, поэтому я не могу с этим поиграться
Ответ №2:
В конце концов, я обошел это, извлек сопоставление из xsd. Это выглядит так:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.lol.com/Standards/lol/1")]
[System.Xml.Serialization.XmlRootAttribute("FatherProvision", Namespace = "http://www.lol.com/Standards/lol/1", IsNullable = false)]
public partial class FatherElement
{
private string FatherClassField;
private object[] itemsField;
private ItemsChoiceType3[] itemsElementNameField;
private string FatherBasisField;
private string FatherRoleField;
private FatherProvision_ExtensionType extensionField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(DataType = "NMTOKEN")]
public string FatherClass
{
get
{
return this.FatherClassField;
}
set
{
this.FatherClassField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("FatherAuthorityLocation", typeof(FatherAuthorityLocationType))]
[System.Xml.Serialization.XmlElementAttribute("FatherType", typeof(string), DataType = "NMTOKEN")]
[System.Xml.Serialization.XmlElementAttribute("FatherTypeDescription", typeof(string))]
[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 ItemsChoiceType3[] ItemsElementName
{
get
{
return this.itemsElementNameField;
}
set
{
this.itemsElementNameField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(DataType = "NMTOKEN")]
public string FatherBasis
{
get
{
return this.FatherBasisField;
}
set
{
this.FatherBasisField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(DataType = "NMTOKEN")]
public string FatherRole
{
get
{
return this.FatherRoleField;
}
set
{
this.FatherRoleField = value;
}
}
/// <remarks/>
public FatherProvision_ExtensionType Extension
{
get
{
return this.extensionField;
}
set
{
this.extensionField = value;
}
}
}
public enum ItemsChoiceType3
{
/// <remarks/>
FatherAuthorityLocation,
/// <remarks/>
FatherType,
/// <remarks/>
FatherTypeDescription,
}
Затем я получаю доступ к элементу, сначала проверяя индекс элемента нужного типа (если таковой имеется) в массиве имен элементов, а затем использую этот индекс для доступа к элементу.
var fatherTypeElement = string.Empty;
var fatherAuthorityLocationElement = (fatherAuthorityLocationType)null;
var fatherTypeElementIndex = Array.IndexOf(fatherProvisionAndPercentage.fatherProvision.ItemsElementName, ItemsChoiceType3.fatherType);
if(fatherTypeElementIndex >= 0)
fatherTypeElement = fatherProvisionAndPercentage.fatherProvision.Items[fatherTypeElementIndex] as string;