Сериализация элементов с множественным выбором из XML в C # - PullRequest
2 голосов
/ 03 апреля 2019

У меня есть эта схема

<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, но генерируемый им код преобразует варианты выбора в элемент объектов типа, и я хотел бы сохранить строгую типизацию.

Есть идеи?

Ответы [ 2 ]

1 голос
/ 03 апреля 2019

В конце концов я справился с этим, извлекая отображение из 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,
}

Затем я получаю доступ к элементу, сначала проверяя индекс элемента нужного типа (если есть) в массиве элемента name, а затем использую этот индекс для доступа к элементу..

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;
1 голос
/ 03 апреля 2019

<xs:choice> по-прежнему проблема при создании классов.Проблема в том, что бокс и наименование выбранного элемента.Я бы предложил обходной путь.

Как я понял, вы хотите выбрать одну из трех возможностей:

  1. Отец имеет Type и может иметь Location и Description

  2. Отец имеет Location и может Description

  3. Отец имеет 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:\Temp\test.xml";
XmlSerializer x = new XmlSerializer(e.GetType());

using (var sw = new StreamWriter(filePath))
    x.Serialize(sw, e);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...